﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
using ICSharpCode.AvalonEdit.Rendering;
using Meta;
using Microsoft.Win32;
using System.Collections.ObjectModel;

namespace MetaEdit
{
	public partial class Editor : Window
	{
		public Editor()
		{
			editor = this;
			InitializeComponent();
			this.Icon = BitmapFrame.Create(new Uri("pack://application:,,,/images/meta.ico", UriKind.RelativeOrAbsolute));

			LoadSettings();

			Background = SystemColors.MenuBarBrush;
			Title = ProgramName;


			BindKeys();		
	

			Closing += delegate(object sender, System.ComponentModel.CancelEventArgs e)
			{
				List<string> files = new List<string>();
				//foreach (Page page in pages)
					foreach (Page page in tabs.Items)
				{
					if (page.changes)
					{
						switch (MessageBox.Show("Save changes to "+System.IO.Path.GetFileName(page.fileName)+"?", ProgramName, MessageBoxButton.YesNoCancel))
						{
							case MessageBoxResult.Yes:
								page.Save();
								break;
							case MessageBoxResult.No:
								break;
							case MessageBoxResult.Cancel:
								e.Cancel = true;
								return;
						}
					}
					files.Add(page.fileName);
				}
				Settings.lastFiles = files.ToArray();
				SaveSettings();
			};

			Loaded += delegate
			{
				if (Settings.lastFiles != null)
				{
					foreach(string file in Settings.lastFiles)
					{
						if (File.Exists(file))
						{
							Open(file);
						}
					}
				}
			};

			this.Drop += delegate(object sender, DragEventArgs e)
			{
				string[] files = (string[])e.Data.GetData("FileDrop");
				foreach (string file in files)
				{
					Open(file);
				}
			};
			//tabs.ItemsSource = pages;
		}

		private void BindKeys()
		{
			InputBindings.Add(new KeyBinding(ApplicationCommands.NotACommand, new KeyGesture(Key.C, ModifierKeys.Control)));

			BindKey(EditorCommands.Up, Key.L, ModifierKeys.Alt);
			BindKey(EditorCommands.Down, Key.K, ModifierKeys.Alt);

			BindKey(ApplicationCommands.Find, Key.F, ModifierKeys.Control);
			BindKey(ApplicationCommands.Find, Key.H, ModifierKeys.Control);
			BindKey(EditingCommands.Backspace, Key.N, ModifierKeys.Alt);
			BindKey(EditingCommands.Delete, Key.M, ModifierKeys.Alt);
			BindKey(EditingCommands.DeleteNextWord, Key.M, ModifierKeys.Alt | ModifierKeys.Control);
			BindKey(EditingCommands.DeletePreviousWord, Key.N, ModifierKeys.Alt | ModifierKeys.Control);
			BindKey(EditingCommands.MoveDownByPage, Key.K, ModifierKeys.Alt | ModifierKeys.Control);
			BindKey(EditingCommands.MoveLeftByCharacter, Key.J, ModifierKeys.Alt);
			BindKey(EditingCommands.MoveRightByCharacter, Key.Oem3, ModifierKeys.Alt);

			BindKey(EditingCommands.MoveLeftByWord, Key.J, ModifierKeys.Alt | ModifierKeys.Control);
			BindKey(EditingCommands.MoveRightByWord, Key.Oem3, ModifierKeys.Alt | ModifierKeys.Control);
			BindKey(EditingCommands.MoveToDocumentEnd, Key.Oem1, ModifierKeys.Alt | ModifierKeys.Control);
			BindKey(EditingCommands.MoveToDocumentStart, Key.U, ModifierKeys.Alt | ModifierKeys.Control);
			BindKey(EditingCommands.MoveToLineEnd, Key.Oem1, ModifierKeys.Alt);
			BindKey(EditingCommands.MoveToLineStart, Key.U, ModifierKeys.Alt);
			BindKey(EditingCommands.MoveUpByPage, Key.L, ModifierKeys.Alt | ModifierKeys.Control);
			BindKey(EditingCommands.SelectDownByLine, Key.K, ModifierKeys.Alt | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectDownByPage, Key.K, ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectLeftByCharacter, Key.J, ModifierKeys.Alt | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectLeftByWord, Key.J, ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectRightByCharacter, Key.Oem3, ModifierKeys.Alt | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectRightByWord, Key.Oem3, ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectToDocumentEnd, Key.Oem1, ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectToDocumentStart, Key.U, ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectToLineEnd, Key.Oem1, ModifierKeys.Alt | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectToLineStart, Key.U, ModifierKeys.Alt | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectUpByLine, Key.L, ModifierKeys.Alt | ModifierKeys.Shift);
			BindKey(EditingCommands.SelectUpByPage, Key.L, ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift);

			this.CommandBindings.AddRange(new CommandBinding[] {
				new CommandBinding(
					EditorCommands.Settings,
					delegate {
						new IDE.Options().ShowDialog();
					}
				),
				new CommandBinding(
					EditorCommands.SetFocus,
					delegate {
						CurrentPage.textBox.Focus();
					}
				),
				new CommandBinding(
					EditorCommands.CloseTab,
					delegate
					{
						//if (pages.Count != 0)
							if (tabs.Items.Count != 0)
						{
							((Page)tabs.SelectedItem).Close(); 
						}
					}
				),
				new CommandBinding(
					ApplicationCommands.Find,
					delegate
					{
						findAndReplace.ShowDialog();
					}
				),
				new CommandBinding(
					ApplicationCommands.New,
					delegate 
					{ 
						this.Open(""); 
					}
				),
				new CommandBinding(
					ApplicationCommands.Open,
					delegate 
					{ 
						Open(); 
					}
				)
			});
		}
		public static Editor editor;
	}
    public class EditorCommands
    {
		public static RoutedUICommand Settings = new RoutedUICommand("Settings...","Settings", typeof(EditorCommands));
		public static RoutedUICommand SetFocus = new RoutedUICommand("Set focus","Set focus", typeof(EditorCommands));
        public static RoutedUICommand InteractiveSearch = new RoutedUICommand("Interactive search","Interactive search",typeof(EditorCommands),new InputGestureCollection(new InputGesture[] {new KeyGesture(Key.I,ModifierKeys.Control)}));
        public static RoutedUICommand ReverseInteractiveSearch = new RoutedUICommand("Reverse interactive search","Reverse interactive search", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.I, ModifierKeys.Control|ModifierKeys.Shift) }));
        public static RoutedUICommand StopInteractiveSearch = new RoutedUICommand("Stop interactive search","Stop interactive search", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.Escape), new KeyGesture(Key.Back)}));

		public static RoutedUICommand Comment = new RoutedUICommand("Comment","Comment", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] {new KeyGesture(Key.Q,ModifierKeys.Control) }));
		public static RoutedUICommand Uncomment = new RoutedUICommand("Uncomment","Uncomment", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] {new KeyGesture(Key.U,ModifierKeys.Control) }));
		public static RoutedUICommand CutLine = new RoutedUICommand("Cut line","Cut line", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] {new KeyGesture(Key.L,ModifierKeys.Control) }));
		public static RoutedUICommand ShowIntellisense = new RoutedUICommand("Show intellisense","Show intellisense", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { }));
		public static RoutedUICommand ShowFunctionIntellisense = new RoutedUICommand("Show intellisense","Show intellisense", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { }));//new KeyGesture(Key.Space, ModifierKeys.Control|ModifierKeys.Shift) 
		public static RoutedUICommand ShowMergedIntellisense = new RoutedUICommand("Show intellisense","Show intellisense", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] {  }));// new KeyGesture(Key.Space, ModifierKeys.Control)
		
		public static RoutedUICommand Compile = new RoutedUICommand("Compile","Compile", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.B,ModifierKeys.Control|ModifierKeys.Shift) }));
		public static RoutedUICommand SetBreakpoint = new RoutedUICommand("Set Breakpoint","Set Breakpoint", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.F9) }));
		public static RoutedUICommand RemoveAllBreakpoints = new RoutedUICommand("Remove all breakpoints","Remove all breakpoints", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.F9,ModifierKeys.Control|ModifierKeys.Shift) }));
		public static RoutedUICommand StartDebugging = new RoutedUICommand("Start Debugging","Start Debugging", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.F5) }));
		public static RoutedUICommand StopDebugging = new RoutedUICommand("Stop Debugging","Stop Debugging", typeof(EditorCommands), new InputGestureCollection(new InputGesture[]{new KeyGesture( Key.F5,ModifierKeys.Shift )}));
		public static RoutedUICommand StartWithoutDebugging = new RoutedUICommand("Start without debugging","Start without debugging", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.F5, ModifierKeys.Control) }));
		public static RoutedUICommand StepInto = new RoutedUICommand("Step Into","Step Into", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.F11) }));
		public static RoutedUICommand StepOver = new RoutedUICommand("Step Over","Step Over", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.F10) }));
		public static RoutedUICommand Combo = new RoutedUICommand("Combo","Combo", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.K,ModifierKeys.Control) }));
		public static RoutedUICommand CancelCombo = new RoutedUICommand("Cancel Combo","Cancel Combo", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.Escape) }));

		public static RoutedUICommand CloseTab = new RoutedUICommand("Close Tab","Close Tab", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] {new KeyGesture(Key.F4,ModifierKeys.Control),new KeyGesture(Key.W,ModifierKeys.Control)}));
		public static RoutedUICommand GoToMatchingBrace = new RoutedUICommand("Go To Matching Brace","Go To Matching Brace", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.I, ModifierKeys.Alt), new KeyGesture(Key.Oem6, ModifierKeys.Control | ModifierKeys.Shift) }));
		public static RoutedUICommand SelectToMatchingBrace = new RoutedUICommand("Select To Matching Brace","Select To Matching Brace", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.I, ModifierKeys.Alt | ModifierKeys.Shift), new KeyGesture(Key.Oem6, ModifierKeys.Control|ModifierKeys.Shift) }));
		public static RoutedUICommand GoToLine = new RoutedUICommand("Go To Line","Go To Line", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.G, ModifierKeys.Control) }));
		public static RoutedUICommand GoToNextError = new RoutedUICommand("Go to next error","Go to next error", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.Z, ModifierKeys.Alt),new KeyGesture(Key.F8) }));

		public static RoutedUICommand Up = new RoutedUICommand("Up","Up", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.L, ModifierKeys.Alt), new KeyGesture(Key.Up) }));
		public static RoutedUICommand Down = new RoutedUICommand("Down","Down", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.K, ModifierKeys.Alt), new KeyGesture(Key.Down) }));
		
		public static RoutedUICommand PageUp = new RoutedUICommand("PageUp","PageUp", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.L, ModifierKeys.Alt|ModifierKeys.Control), new KeyGesture(Key.PageUp) }));
		public static RoutedUICommand PageDown = new RoutedUICommand("PageDown","PageDown", typeof(EditorCommands), new InputGestureCollection(new InputGesture[] { new KeyGesture(Key.K, ModifierKeys.Alt|ModifierKeys.Control), new KeyGesture(Key.PageDown) }));
	}
	public partial class App : System.Windows.Application
	{
		public static App app;
		[STAThread]
		public static void Main(string[] parameters)
		{
			app=new App();
			Editor editor = new Editor();
			app.MainWindow = editor;
			app.ShutdownMode = ShutdownMode.OnMainWindowClose;
			foreach (string file in parameters)
			{
				editor.Open(file);
			}
			app.Run(editor);
		}
	}
	public class InteractiveSearch
	{
		public bool Active
		{
			get;
			set;
		}
		public string oldText = "";
		public void Back()
		{
			text = text.Substring(0, Math.Max(0, text.Length - 1));
			oldText = text;
			Find(-direction);
		}
		public void OnKeyDown(TextCompositionEventArgs e)
		{
			text += e.Text;
			Find(direction);
			oldText = text;

			e.Handled = true;
		}
		public bool Searching = false;
		public void Find(int direction)
		{
			this.direction = direction;
			Searching = true;
			int start = textBox.SelectionStart;
			int searched = 0;
			if (text.Length > 0)
			{
				while (true)
				{
					int end = start + text.Length;
					if (end >= textBox.Text.Length || end < 0)
					{
						if (direction == 1)
						{
							end = textBox.Text.Length-1;
						}
						else
						{
							end = textBox.Text.Length - 1;
						}
					}
					if (textBox.Text.Substring(start,end-start).ToLower().StartsWith(text.ToLower()) 
						&& (start!=textBox.SelectionStart || textBox.SelectedText.Length != text.Length))
					{
						textBox.Select(start,end-start);
						break;
					}
					if (start==searchStart && searched != 0)
					{
						break;
					}
					start = start + direction;
					if (start >= textBox.Text.Length || start < 0)
					{
						if (direction == 1)
						{
							start = 0;
						}
						else
						{
							start = textBox.Text.Length-1;
						}
					}
					searched++;
				}
			}
			Searching = false;
			textBox.ScrollToCursor();
		}
		// TODO: remove?
		public string text
		{
			get
			{
				return _text;
			}
			set
			{
				_text = value;
				searchStart = textBox.SelectionStart;
			}
		}
		private int searchStart;
		private string _text = "";
		private int start;
		private int direction;
		public Box textBox
		{
			get;
			set;
		}
		public InteractiveSearch(int direction, Box box)
		{
			this.textBox = box;
			this.direction = direction;
			start = 0;
		}
	}
	//public class Item
	//{
	//    public Map Key
	//    {
	//        get;
	//        set;
	//    }
	//    public Map Value
	//    {
	//        get;
	//        set;
	//    }
	//    public static BitmapImage method = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Method.png"));
	//    public static BitmapImage properties = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Properties.png"));
	//    public static BitmapImage events = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Event.png"));
	//    public static BitmapImage classes = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Class.png"));
	//    public static BitmapImage assembly = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Assembly.png"));
	//    public Item(Map key, Map value)
	//    {
	//        this.Key = key;
	//        this.Value = value;
	//    }
	//    public BitmapImage Image
	//    {
	//        get
	//        {
	//            BitmapImage source=null;
	//            if (this.Value != null)
	//            {
	//                if (this.Value is Method)
	//                {
	//                    source = method;
	//                }
	//                else if (this.Value is PropertyMap)
	//                {
	//                    source = properties;
	//                }
	//                else if (this.Value is EventMap)
	//                {
	//                    source = events;
	//                }
	//                else if (this.Value is TypeMap)
	//                {
	//                    source = classes;
	//                }
	//                else if (this.Value is AssemblyMap)
	//                {
	//                    source = assembly;
	//                }
	//                else
	//                {
	//                    if (this.Value.ContainsKey(CodeKeys.Program))
	//                    {
	//                        source = method;
	//                    }
	//                }
	//            }
	//            return source;
	//        }

	//    }
	//}
	public class Box : TextEditor
	{
		private Meta.Expression _parsed;
		public Meta.Expression Parsed
		{
			get
			{
				if (_parsed == null)
				{
					try
					{
						_parsed = Parser.ParseString(this.Text, "").GetExpression();
					}
					catch (SyntaxException e)
					{
						_parsed = null;
					}
				}
				return _parsed;
			}
			set
			{
				_parsed = value;
			}
		}

		int? selectionStart = null;
        public const string comment="//";
        InsightWindow insight;
		public void ScrollToCursor()
		{
			ScrollToLine(Document.GetLocation(SelectionStart).Line);
		}
		public bool IntellisenseVisible()
		{
			return Editor.CurrentPage.textBox.intellisense!=null;// && Editor.CurrentPage.textBox.intellisense.IsActive;
		}
		public CompletionWindow intellisense;
		public bool keyCombo = false;	
		private Editor.Page page;
		public int historyIndex = -1;
		public Box(Editor.Page page):base()
		{
			//this.Height = 800;
			this.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
			this.WordWrap = false;
			this.Background = Brushes.White;
			this.PreviewKeyDown += new KeyEventHandler(Box_PreviewKeyDown);
			this.TextInput += new TextCompositionEventHandler(Box_TextInput);
			
			IHighlightingDefinitionReferenceResolver x=new HighlightingManager();
			this.SyntaxHighlighting = HighlightingLoader.Load(XmlReader.Create(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "meta.xshd")), x);
			this.Loaded += new RoutedEventHandler(delegate { this.Focus(); });
			this.page=page;
			this.KeyDown += new KeyEventHandler(delegate(object sender, KeyEventArgs e)
			{
				

				if (keyCombo)
				{
					if (e.KeyboardDevice.Modifiers == ModifierKeys.Control)
					{
						if (e.Key == Key.C)
						{
							EditorCommands.Comment.Execute(null, this);
							e.Handled = true;
							keyCombo = false;
						}
						else if (e.Key == Key.U)
						{
							EditorCommands.Uncomment.Execute(null, this);
							e.Handled = true;
							keyCombo = false;
						}
					}
				}
				else if (e.Key == Key.C && e.KeyboardDevice.Modifiers == ModifierKeys.Control)
				{
					ApplicationCommands.Copy.Execute(null, this);
				}
				else if (e.Key == Key.Space && e.KeyboardDevice.Modifiers == ModifierKeys.Control)
				{
					selectionStart = this.SelectionStart;
					//EditorCommands.ShowMergedIntellisense.Execute(null, this);
				}
				else if (e.Key == Key.D8 && e.KeyboardDevice.Modifiers == ModifierKeys.Shift)
				{
					selectionStart = this.SelectionStart + 1;
					//EditorCommands.ShowMergedIntellisense.Execute(null, this);
				}
				//else if (e.Key == Key.D8 && e.KeyboardDevice.Modifiers == ModifierKeys.Shift)
				//{
				//    EditorCommands.ShowMergedIntellisense.Execute(null, this);
				//}
			});
			this.TextInput += new TextCompositionEventHandler(Box_PreviewTextInput);
			interactiveSearch = new InteractiveSearch(1, this);
			this.PreviewTextInput+=new TextCompositionEventHandler(delegate(object sender,TextCompositionEventArgs e)
			{
				if (interactiveSearch.Active)
				{
					interactiveSearch.OnKeyDown(e);
				}
			});

			this.InputBindings.AddRange(new KeyBinding[] {
				new KeyBinding(ApplicationCommands.NotACommand, new KeyGesture(Key.LeftShift, ModifierKeys.Control)),
				new KeyBinding(ApplicationCommands.NotACommand, new KeyGesture(Key.None, ModifierKeys.Control|ModifierKeys.Shift)),
				new KeyBinding(ApplicationCommands.NotACommand, new KeyGesture(Key.C, ModifierKeys.Control)),
				new KeyBinding(ApplicationCommands.NotACommand, new KeyGesture(Key.L, ModifierKeys.Control)),
				new KeyBinding(ApplicationCommands.NotACommand, new KeyGesture(Key.U, ModifierKeys.Control)),
				//new KeyBinding(ApplicationCommands.NotACommand, new KeyGesture(Key.L, ModifierKeys.Alt)),
				//new KeyBinding(ApplicationCommands.NotACommand, new KeyGesture(Key.K, ModifierKeys.Alt)),
				new KeyBinding(EditorCommands.ReverseInteractiveSearch, new KeyGesture(Key.I, ModifierKeys.Control|ModifierKeys.Shift)),
                new KeyBinding(EditorCommands.CutLine, new KeyGesture(Key.L, ModifierKeys.Control))
			});
			
			this.CommandBindings.AddRange(new CommandBinding[] {
				new CommandBinding(
					EditorCommands.GoToNextError,
					delegate{
						Editor.editor.errorList.SelectedIndex=(Editor.editor.errorList.SelectedIndex+1)%Editor.editor.errorList.Items.Count;
					}
				),
				new CommandBinding(
				    EditorCommands.Compile,
				    delegate {
						Editor.editor.message.Content="Building...";
						
				        Editor.editor.message.Content = page.Compile(false) ? "Build succeeded":"Build failed";
				    }
				),
				new CommandBinding(
					EditorCommands.PageUp, 
					delegate
					{
						EditingCommands.MoveUpByPage.Execute(null, (IntellisenseVisible()?(IInputElement)this.intellisense:(IInputElement)this));
					}
				),
				new CommandBinding(
					EditorCommands.PageDown, 
					delegate 
					{
						EditingCommands.MoveDownByPage.Execute(null, IntellisenseVisible()?(IInputElement)this.intellisense:(IInputElement)this);
					}
				),
				new CommandBinding(
					EditorCommands.Up,
					delegate
					{
						if(IntellisenseVisible())
						{
							if(this.intellisense.CompletionList.ListBox.SelectedIndex>0)
							{
								this.intellisense.CompletionList.ListBox.SelectedIndex--;
								this.intellisense.CompletionList.ListBox.ScrollIntoView(this.intellisense.CompletionList.ListBox.SelectedItem);
							}
						}
						else
						{
							TextLocation location=this.Document.GetLocation(this.SelectionStart);
							if(location.Line>1)
							{
								this.Select(this.Document.GetOffset(location.Line-1,location.Column),0);
								this.ScrollTo(location.Line-1,0);// .ScrollToLine(location.Line-1);
							}
						}
					}
				),
				new CommandBinding(
					EditorCommands.Down,
					delegate
					{
						if(IntellisenseVisible())
						{
							if(this.intellisense.CompletionList.ListBox.SelectedIndex<this.intellisense.CompletionList.ListBox.Items.Count-1)
							{
								this.intellisense.CompletionList.ListBox.SelectedIndex++;
								this.intellisense.CompletionList.ListBox.ScrollIntoView(this.intellisense.CompletionList.ListBox.SelectedItem);
							}
						}
						else
						{
							TextLocation location=this.Document.GetLocation(this.SelectionStart);
							if(location.Line<this.LineCount)
							{
								this.Select(this.Document.GetOffset(location.Line+1,location.Column),0);
								this.ScrollTo(location.Line+1,0);
								//this.ScrollToLine(location.Line+1);
							}
						}
					}
				),
				new CommandBinding(
					EditorCommands.ReverseInteractiveSearch,
					delegate
					{
						StartInteractiveSearch(-1);
					}
				),
				new CommandBinding(
					EditorCommands.StopInteractiveSearch,
					delegate
					{
						StopInteractiveSearch();
					}
				),
				new CommandBinding(
					ApplicationCommands.NotACommand, 
					delegate
					{
					}
				),
				new CommandBinding(
					EditorCommands.InteractiveSearch, 
					delegate
					{
						StartInteractiveSearch(1);
					}
				),
				new CommandBinding(
					EditorCommands.Combo, 
					delegate
					{
						keyCombo = true;
					}
				),
				new CommandBinding(
					EditorCommands.Comment,
					delegate(object sender, ExecutedRoutedEventArgs e)
					{
						page.MassEdit(true,comment);
					}
				),
				new CommandBinding(
					EditorCommands.Uncomment,
					delegate
					{
						page.MassEdit(false,comment);
					}
				),
				new CommandBinding(
					EditorCommands.CutLine,
					delegate
					{
						var line = Document.GetLineByOffset(SelectionStart).LineNumber;
						if(line < Document.LineCount)
						{
							int start = Document.GetOffset(line, 1);
							int end = Document.GetOffset(line+1, 1);
							this.SelectionStart=start;
							this.SelectionLength=end-start;
							this.Cut();
						}
					}
				),
				new CommandBinding(
					EditorCommands.ShowIntellisense, 
					delegate
					{
						try
						{
							if(interactiveSearch.Active)
							{
								return;
							}
							selectionStart=this.SelectionStart;
							string text=this.Text;
							new Action<Page>(delegate {
								var all= StartIntellisenseAll(page,(int)selectionStart,text);
							
								if(all.Count==0)
								{
									return;
								}
								Meta.Expression start = GetCorrectExpression(all,selectionStart.Value);		
								Meta.Expression e=null;
								e = start;
								//foreach(var a in all)
								//{
								//    if(a is Select)
								//    {
								//        e=a;
								//        break;
								//    }
								//}
								//Meta.Expression e = StartIntellisense(page,selectionStart,text);
								//while(true)
								//{
								//    if (e == null)
								//    {
								//        break;
								//    }
								//    if (e is Select)
								//    {
								//        break;
								//    }
								//    else
								//    {
								//        e = e.Parent;
								//    }
								//}

								while(!(e is Select ) && e !=null)
								{
									e = e.Parent;
								}
								if (e is Select)
								{
									this.Dispatcher.Invoke(new Action(delegate {
										DisplayIntellisense(e,false);
									}),null);
								}
							}).BeginInvoke(null,null,null);
					
						}
						catch(Exception e)
						{
						}
					}
				),
				new CommandBinding(
					EditorCommands.ShowMergedIntellisense,
					delegate
					{
						try
						{
							if (interactiveSearch.Active)
							{
								return;
							}
							string text=this.Text;
							//selectionStart = this.SelectionStart;
							//selectionStart = this.SelectionStart;
							//while(selectionStart>0 && char.IsLetterOrDigit(Text[selectionStart]))
							//{
							//    selectionStart--;
							//}
							int lineStart = text.LastIndexOf('\n', SelectionStart);
							int comment = text.LastIndexOf("//", SelectionStart);
							if(comment > lineStart)
							{
								return;
							}
							new Action(delegate {

								//selectionStart = SelectionStart;

								Meta.Expression e=null;
								var expressions = StartIntellisenseAll(page, (int)selectionStart+1, text);
								if(expressions.Count==0)
								{
									return;
								}
								//if (expressions.Count == 0 || (expressions[0] is Literal && !(expressions[0].Parent is Search)))
								//{
								//    return;
								//}
								var expression = GetCorrectExpression(expressions,selectionStart.Value);
								while (!(expression is Program) && expression != null)
								{
									//if(expression.Statement!=null)
									//{
									//    expression = expression.Statement.GetProgram();
									//}
									//else
									//{
										expression = expression.Parent;
									//}

								}
								e = expression;
								//foreach (var a in expressions)
								//{
								//    if (a is Program)
								//    {
								//        e = a;
								//        break;
								//    }
								//}
								//Meta.Expression e = StartIntellisense(page,selectionStart,text);
								//while(true)
								//{
								//    if (e == null)
								//    {
								//        break;
								//    }
								//    if (e is Program)
								//    {
								//        break;
								//    }
								//    else
								//    {
								//        e = e.Parent;
								//    }
								//}
								if(e is Program)
								{
									Dispatcher.Invoke(
										new Action( delegate {
											try
											{
												DisplayIntellisense(e,true);
											}
											catch
											{
											}
										}));
								}
							}).BeginInvoke(null,null);
						}
						catch
						{
						}
					}
				),
				new CommandBinding(
				    EditorCommands.ShowFunctionIntellisense,
				    delegate
				    {
				        try
				        {
							if (interactiveSearch.Active)
							{
								return;
							}
							string text=this.Text;
							int selectionStart=this.SelectionStart;
							new Action(delegate {
								var all = StartIntellisenseAll(page, selectionStart, text);
								//Meta.Expression ex = StartIntellisense(page, selectionStart, text);

								if(all.Count==0)
								{
									return;
								}
								var ex = GetCorrectExpression(all,selectionStart);
								Meta.Expression e = ex;
								int callDepth = 1;


								while(true)
								{
									if (e == null)
									{
										break;
									}
									if (e is Call)
									{
										break;
									}
									else
									{
										e = e.Parent;
									}
								}
								if (e is Call)
								{
									Call call = (Call)e;
									

									if(call.argument==ex || call.argument == ex.Parent)
									{
										callDepth++;
									}
									
									//while
										
									//}
									while(call.function is Call)
									{
										call=(Call)call.function;
										callDepth++;
									}
									Map s = Simulate(call.function);
									//Map s = Simulate(call.function);


									Meta.Expression expression=call;
									//while(expression is Call)
									//{
									//    expression = ((Call)expression).function;
										
									//}
									
									if(s!=null)
									{
											Dispatcher.Invoke(new Action(delegate {
												object description = Completion.GetDescription(s, callDepth);
                                                if (insight != null)
                                                {
                                                    insight.Close();
                                                }
												insight=new InsightWindow(this.TextArea);
												//TextBlock label=new TextBlock();
												//label.Inlines.Clear();												
												//label.Inlines.Add(new Run(summary.GetString()));
												//insight.Content=label;
												//label.Margin=new Thickness(0);
												//label.Padding=new Thickness(0);

												if (description != null)
												{

												insight.Content=description;
												//insight.Content=summary.GetString();
												//insight.Content="hello!!!!!!!!!!";

												// do this everywhere
                                                if (call.Source != null && call.Source.Start != null && call.Children.Any() && call.Children.First().Source != null)
												{
													insight.StartOffset=call.Children.First().Source.End.Index+1;
												}
												else
												{
													// TODO: why isn't the source set sometimes?
												}


													insight.CloseAutomatically=true;

													insight.Show();

												}

												// TODO: do this everywhere
												if(intellisense!=null)
												{
													intellisense.Close();
												}
											}));
									}

									return;

									Method method = s as Method;
									if (method != null)
									{
										Dispatcher.Invoke(new Action(delegate {
											insight=new InsightWindow(this.TextArea);
											TextBlock label=new TextBlock();
											label.Inlines.Clear();
											
											label.Inlines.Add(new Run(Editor.Page.GetSignature(method)));
											label.Inlines.AddRange(Comments.GetComment(method.method).GetParameters());

											insight.Content=label;

											//insight.Content="hello!!!!!!!!!!";
											insight.Show();
										}));
									}
									else if(s!=null && s.ContainsKey(CodeKeys.Program)
										&& s.ContainsKey(Editor.DocumentationKeys.Documentation))
									{
										Map documentation=s[Editor.DocumentationKeys.Documentation];
										Map summary=documentation[Editor.DocumentationKeys.Summary];
										if(summary!=null)
										{
											Dispatcher.Invoke(new Action(delegate {
												insight=new InsightWindow(this.TextArea);
												//TextBlock label=new TextBlock();
												//label.Inlines.Clear();												
												//label.Inlines.Add(new Run(summary.GetString()));
												//insight.Content=label;
												//label.Margin=new Thickness(0);
												//label.Padding=new Thickness(0);
												insight.Content=summary.GetString();
												//insight.Content="hello!!!!!!!!!!";

												// do this everywhere
												if(call.Source!=null && call.Source.Start!=null && call.Children.Any() && call.Children.First().Source!=null)
												{
                                                    insight.StartOffset = call.Children.First().Source.Start.Index;
                                                    //insight.StartOffset = call.Source.Start.Index;
                                                }
												else
												{
													// TODO: why isn't the source set sometimes?
												}
												insight.CloseAutomatically=true;

												insight.Show();
												// TODO: do this everywhere
												if(intellisense!=null)
												{
													intellisense.Close();
												}
											}));
										}
									}
								}
							}).BeginInvoke(null,null);
				        }						
				        catch
				        {
				        }
				    }
				)
			});
			this.PreviewMouseUp += delegate
			{
				UpdateStatus();
			};
			this.KeyUp+=delegate (object sender,KeyEventArgs e)
			{
				if (!interactiveSearch.Active)
				{
					if (e.Key == Key.OemPeriod && e.KeyboardDevice.Modifiers!=ModifierKeys.Shift)
					{
						if (intellisense != null)
						{
							intellisense.Close();
						}
						//EditorCommands.ShowIntellisense.Execute(null, this);
					}
				}
			};
			this.TextChanged += delegate
			{
				this.page.changes = true;
			};
			this.KeyUp += delegate
			{
				UpdateStatus();
			};
			this.PreviewKeyDown+=delegate(object sender,KeyEventArgs e) 
			{
				if (e.Key==Key.LeftShift)
				{
					e.Handled = true;
				}
				if (!interactiveSearch.Active)
				{
					//if (e.Key == Key.OemPeriod && e.KeyboardDevice.Modifiers!=ModifierKeys.Shift)
					//{
					//    EditorCommands.ShowIntellisense.Execute(null, this);
					//}
					// TODO: make independent of keyboard layout
					if (e.Key == Key.D9 && e.KeyboardDevice.Modifiers == ModifierKeys.Shift)
					{
						//MetaDevelop.Editor.Page.intellisense.IsOpen = false;
						//MetaDevelop.Editor.Page.intellisense = false;
						//page.tip.IsOpen = false;
						//EditorCommands.ShowFunctionIntellisense.Execute(null, this);
                        if (insight != null)
                        {
                            insight.Close();
                        }
					}
					else if (e.Key == Key.Space)
					{
						//if (e.KeyboardDevice.Modifiers == ModifierKeys.Control)
						//{
						//    EditorCommands.ShowMergedIntellisense.Execute(null, this);
						//    //EditorCommands.ShowFunctionIntellisense.Execute(null, this);
						//}
						//else 
						if (e.KeyboardDevice.Modifiers == (ModifierKeys.Control | ModifierKeys.Shift))
						{
							selectionStart = SelectionStart;
							//EditorCommands.ShowFunctionIntellisense.Execute(null, this);
							e.Handled = true;
						}
						else if (e.KeyboardDevice.Modifiers == ModifierKeys.Control)
						{
							selectionStart = SelectionStart;
							//EditorCommands.ShowMergedIntellisense.Execute(null, this);
							e.Handled = true;
						}
						else
						{
							// TODO: put this into the command?
							selectionStart = SelectionStart;
							//EditorCommands.ShowFunctionIntellisense.Execute(null, this);

							// TODO: is this needed?
							//e.Handled = true;
						}
					}
                    else if (e.Key == Key.D9 && e.KeyboardDevice.Modifiers==ModifierKeys.Shift)
                    {
                        
                    }
				}
			};
			//this.TextArea.TextView.LineTransformers.Add(new IndentColorizer(this.TextArea.TextView));
			//this.Background = new SolidColorBrush(HlsValueConverter.HlsToRgb(new HlsValueConverter.HlsColor() { A = 0.5, H = 20, L = 0.8, S = 0.2 * (double)(0% 5) }));
		}

		void Box_TextInput(object sender, TextCompositionEventArgs e)
		{
			string text = e.Text;
			switch (text)
			{
				case ")":
				case "}":
				case "]":
					int start = this.page.FindMatchingBrace();
					if (start == -1)
					{
						break;
					}

					var line=Document.GetLineByOffset(start);
						string indentation = Editor.GetIndentation(line.Text);
						var currentLine = Document.GetLineByOffset(SelectionStart);
						if (currentLine.Text.Trim().Length == 1)
						{

						this.Select(currentLine.Offset, this.SelectionStart - currentLine.Offset);
						this.SelectedText = indentation + text;
						//this.SelectedText = indentatio n + lineEnd;
						this.Select(SelectionStart + SelectedText.Length, 0);
						e.Handled = true;
					}
					break;
			}

		}

		void Box_PreviewKeyDown(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Return)
			{
				var line=this.Document.GetLineByOffset(SelectionStart).Text.TrimEnd();
				//this.LineCount
				//int i = this.Text.LastIndexOfAny(new char[] {'\r','\n'}, 0);
				//int b = this.Text.IndexOfAny(new char[] {'\r','\n'}, SelectionStart);
				//if (i == -1)
				//{
				//    i = 0;
				//}
				//if (b == -1)
				//{
				//    b = this.Text.Length - 1;
				//}
				//string line = Text.Substring(i, b - i).TrimEnd();

				if (line.Length > 0)
				{
					var lineEnd=line[line.Length - 1].ToString();
					switch (lineEnd)
					{
						case "(":
						case "{":
						case "[":
							this.Select(this.SelectionStart, 0);
							this.SelectedText = "\r\n" + Editor.GetIndentation(line) + "\t";
							this.Select(SelectionStart+SelectedText.Length, 0);
							e.Handled = true;
							break;
					}
				}
			}
			
		}
		public Meta.Expression GetCorrectExpression(List<Meta.Expression> all,int selectionStart)
		{
			Meta.Expression start = all.Last();
			while (true)
			{
				var old = start;
				if (start is Program)
				{
					// TODO: also consider keys
					foreach (Statement s in ((Program)start).statementList)
					{
						// TODO: look up before . has been pressed and remove + 1
						if (s.value.Source.Start.Index <= selectionStart && s.value.Source.End.Index + 1 >= selectionStart)
						//if (s.value.Source.Start.Index <= selectionStart && s.value.Source.End.Index + 1 >= selectionStart)
						{
							// add parents
							s.value.Parent = start;
							start = s.value;
							break;
						}
						KeyStatement keyStatement = s as KeyStatement;
						if (keyStatement != null)
						{
							if (keyStatement.key.Source.Start.Index <= selectionStart && keyStatement.key.Source.End.Index + 1 >= selectionStart)
							{
								// add parents
								keyStatement.key.Parent = start;
								start = keyStatement.key;
								break;
							}
						}
					}
				}
				else
				{
					foreach (Meta.Expression expression in start.Children)
					{
						if (expression.Source != null && expression.Source.Start.Index <= selectionStart && expression.Source.End.Index >= selectionStart)
						//if (expression.Source != null && expression.Source.Start.Index <= selectionStart && expression.Source.End.Index + 1 >= selectionStart)
						{
							// correct missing parents
							expression.Parent = start;
							start = expression;
							break;
						}
					}
				}
				if (start == old)
				{
					break;
				}
			}
			return start;
		}
		void Box_PreviewTextInput(object sender, TextCompositionEventArgs e)
		{
			string s = e.TextComposition.Text;
			if(s.Length==1 && char.IsLetter(s[0]) && (intellisense==null || !intellisense.IsVisible))// intellisense.Visibility!=System.Windows.Visibility.Visible))
			{
				selectionStart = this.SelectionStart-1;
				//EditorCommands.ShowMergedIntellisense.Execute(null, this);
			}
		}
		public void UpdateStatus()
		{
			TextLocation location = Document.GetLocation(SelectionStart);
			Editor.editor.lineInfo.Content = "Line " + location.Line + ", Col " + location.Column;
		}
		private Meta.Expression StartIntellisense(Editor.Page page, int selectionStart, string text)
		{
			return StartIntellisenseAll(page,selectionStart,text).FirstOrDefault();
		}
		private List<Meta.Expression> StartIntellisenseAll(Editor.Page page,int selectionStart,string text)
		{
			Interpreter.simulate = true;
			Interpreter.profiling = false;
			foreach (Dictionary<Parser.ParserState, Parser.CachedResult> cached in Parser.allCached)
			{
				cached.Clear();
			}
			Meta.Expression.sources.Clear();
			Map.sources.Clear();
			Parser parser = new Parser(text, page.fileName);
			Map map = null;
			bool matched = Parser.Value.Match(parser, ref map);
			KeyStatement.intellisense = true;
			if (!matched)
			{
				return new List<Meta.Expression>();
			}
			Meta.Expression x = map.GetExpression();
			Meta.Expression e = x;
			int index = selectionStart;

			List<Meta.Expression> all = new List<Meta.Expression>();
			foreach (var t in Meta.Expression.sources.Values)
			{
				all.AddRange(t);
			}
			var found=all.Where(a => a!=null && a.Source!=null && a.Source.Start!=null && a.Source.End!= null && a.Source.Start.Index <= index && a.Source.End.Index >= index-2);
			var results=new List<Meta.Expression>(found.OrderBy(a=>a.Parent!=null?0:1).OrderBy(a => a.Source.End.Index - a.Source.Start.Index));

			if (results.Count != 0)
			{
				if (results[0] is Literal)
				{
					if (results.Count > 0)
					{
						var next=results[1];
						if (next.Source.Start.Index != results[0].Source.Start.Index)
						{
							return new List<Meta.Expression>();
						}
					}
				}
			}

			return results;
		}
		public class Completion : ICompletionData
		{
			private Map key;
			private Map value;
			public Completion(Map key,Map value)
			{
				this.key = key;
				this.value=value;
			}
			public void Complete(ICSharpCode.AvalonEdit.Editing.TextArea textArea, ISegment completionSegment, EventArgs insertionRequestEventArgs)
			{
				string s=new Search(new Literal(key)).ToString(); ;
					//string s = this.key.ToString();
				Editor.CurrentPage.textBox.Select(completionSegment.Offset, completionSegment.Length);// .SelectionStart -= completionSegment.Length;
				//if (s.IndexOfAny(Parser.lookupStringForbidden.ToCharArray()) != -1 || (s.Length > 0 && Parser.lookupStringForbiddenFirst.Contains(s[0])))
				//{
				//    s = "<\"" + s.Replace("\"", "\\\"") + "\">";
				//}
				textArea.Selection.ReplaceSelectionWithText(textArea, s);
				//}
				//if(key.IsString)
				//{
				//    string s=this.key.ToString();
				//    Editor.CurrentPage.textBox.Select(completionSegment.Offset,completionSegment.Length);// .SelectionStart -= completionSegment.Length;
				//    if (s.IndexOfAny(Parser.lookupStringForbidden.ToCharArray())!=-1 || (s.Length>0 && Parser.lookupStringForbiddenFirst.Contains(s[0])))
				//    {
				//        s = "<\""+s.Replace("\"","\\\"")+"\">";
				//    }
				//    textArea.Selection.ReplaceSelectionWithText(textArea, s);
				//}
			}
			private object content;
			public object Content
			{
				get
				{
					if (content == null)
					{

						content = new Label()
						{
							//Margin = new Thickness(2),
							//FontSize = 12,
							Content = new TextBlock() { Text = key.ToString() },
							//Background = this.value.ContainsKey(CodeKeys.Program) ? Brushes.Red : Brushes.White
							//Background = this.value.ContainsKey(CodeKeys.Program) ? Brushes.Red : Brushes.White
						};
						//content = new TextBlock()
						//{
						//    Margin=new Thickness(2),
						//    FontSize=12,
						//    Text = key.ToString(),
						//    //Background = this.value.ContainsKey(CodeKeys.Program) ? Brushes.Red : Brushes.White
						//                            //Background = this.value.ContainsKey(CodeKeys.Program) ? Brushes.Red : Brushes.White
						//};
						//(content as TextBlock).PreviewKeyDown+=new KeyEventHandler(delegate(object sender, KeyEventArgs e)
						//    {
						//        if (e.Key == Key.Return)
						//        {
						//            e.Handled = true;
						//        }
						//    });
						
					}
					return content;
					//return key.ToString();
				}
			}

			public object Description
			{
				get
				{
					return GetDescription(value,0);
				}
			}

			public static object GetDescription(Map value,int index)
			{
				TypeMap typeMap = value as TypeMap;
				if (typeMap != null)
				{
					return (Comments.GetComment(typeMap.Type).GetSummary()).Trim();

					//return ("class " +
					//    typeMap.Type.Namespace +
					//    "." +
					//    typeMap.Type +
					//    "\n" +
					//    Comments.GetComment(typeMap.Type).GetSummary()).Trim();
					//ConstructorInfo[] constructors = typeMap.Type.GetConstructors();
					//if (constructors.Length != 0)
					//{								//if (label.Text != "")
					//{
					//}
					//}
					//ConstructorInfo[] constructors=typeMap.Type.GetConstructors();
					//if (constructors.Length != 0)
					//{
					//    label.Text = Comments.GetComment(constructors[0]).Summary.InnerXml;
					//}
				}
				else
				{
					Method method = value as Method;
					PropertyMap property = value as PropertyMap;
					EventMap eventMap = value as EventMap;
					if (property != null)
					{
						return Comments.GetComment(property.property).GetSummary();
						//return Editor.Page.GetTypeName(property.property.PropertyType) + " " + property.property.Name + "\n" + Comments.GetComment(property.property).GetSummary();
					}
					else if (eventMap != null)
					{
						return Comments.GetComment(eventMap.eventInfo).GetSummary();
						//return "event " + eventMap.eventInfo.Name + "\n" + Comments.GetComment(eventMap.eventInfo).GetSummary();
					}
					else if (method != null)
					{
						Comments comment = Comments.GetComment(method.method);

						//string text = Editor.Page.GetSignature(method);

						string text = "";
						//if (method.method is MethodInfo)
						//{
						//    text += GetTypeName(((MethodInfo)method.method).ReturnParameter.ParameterType) + " ";
						//}
						//else
						//{
						//    text += ((ConstructorInfo)method.method).DeclaringType.Name + ".";
						//}
						//text += method.method.Name.Trim();
						TextBlock description = new TextBlock();

						int i=0;
						foreach (var parameter in method.method.GetParameters())
						{
							if (i != 0)
							{
								description.Inlines.Add("\n");
							}
							if (i+1 == index)
							{
								description.Inlines.Add(new Bold(new Run() { Text = parameter.Name }));
							}
							else
							{
								description.Inlines.Add(parameter.Name);
							}
							description.Inlines.Add(
								": " + 
								
								 
								 ((comment!=null && comment.Parameters!=null && comment.Parameters.Count>i)?
								comment.Parameters[i].InnerText.Trim() : "") + " (" + Editor.Page.GetTypeName(parameter.ParameterType) + ")");// + Editor.Page.GetTypeName(parameter.ParameterType)).ToArray());
							i++;

						}

						//text += " "+string.Join("\n",
						//    method.method.GetParameters().Select(parameter => 
						//        parameter.Name + ": "+ 
						//        Editor.Page.GetTypeName(parameter.ParameterType)).ToArray());
						//text += "(" + string.Join("\n", method.method.GetParameters().Select(parameter => GetTypeName(parameter.ParameterType) + " " + parameter.Name).ToArray()) + ")";
						//return text;


						description.Inlines.Add(("\n"+comment.GetSummary()).TrimEnd());
						//text += "\n\n" + comment.GetSummary();
						return description;
						//return text.Trim();
					}
					else
					{
						TextBlock description = new TextBlock();
						try
						{
							Map current = value;
							Dictionary<string,int> arguments = new Dictionary<string,int>();
							int i = 1;
							while (true)
							{
								if (current.ContainsKey(CodeKeys.Program))
								{
									Map program = current[CodeKeys.Program];
									if (program.ContainsKey(1) && program[1].ContainsKey(CodeKeys.Key))
									{
										Map key = program[1][CodeKeys.Key];
										if (key.ContainsKey(CodeKeys.Literal))
										{
											if (key[CodeKeys.Literal].IsString)
											{
												string text = key[CodeKeys.Literal].GetString();
												arguments[text]=i;
												//arguments.Add(text);
												//description += text;
												//description += "|";
												if (program.ContainsKey(2) && program[2].ContainsKey(CodeKeys.Current) && program[2].ContainsKey(CodeKeys.Value))
												{
													Map p = program[2][CodeKeys.Value];
													if (p.ContainsKey(CodeKeys.Literal))
													{
														current = program[2][CodeKeys.Value][CodeKeys.Literal];
														i++;
														continue;
													}
												}
											}
										}
									}
								}
								break;
							}
							if (value.ContainsKey(Editor.DocumentationKeys.Documentation) && value[Editor.DocumentationKeys.Documentation].ContainsKey(Editor.DocumentationKeys.Summary))
							{
								Map documentation = value[Editor.DocumentationKeys.Documentation];
								string summary = documentation[Editor.DocumentationKeys.Summary].GetString();

								//foreach (var x in summary.Split('\''))
								//{
								//    if (arguments.Keys.Contains(x))
								//    {
								//        description += x;
								//    }
								//    else
								//    {
								//        description += x;
								//    }
								//}

								//description += "\n";

								Map arg;
								if (documentation.ContainsKey(Editor.DocumentationKeys.Arguments))
								{
									arg=documentation[Editor.DocumentationKeys.Arguments];
								}
								else
								{
									arg=EmptyMap.Empty;
								}
								var stuff = arg.Select(a => a.Key.GetString()).Union(arguments.Keys);


								foreach (var entry in stuff)
								{
									string name = entry;
									if (arguments.ContainsKey(entry) && arguments[entry] == index)
									{
										description.Inlines.Add(new Bold(new Run() { Text = name}) { });
									}
									else
									{
										description.Inlines.Add(name);
									}
									//description += entry + ": ";
									//if (arguments.ContainsKey(entry) && arguments[entry] == index)
									//{
									//    description += "___";
									//}
									string s;
									if (arg.ContainsKey(entry))
									{
										s = arg[entry].GetString();
									}
									else
									{
										s = entry;
									}
									if (name != "")
									{
										description.Inlines.Add(": " + s + "\n");
									}
								}
								if (description.Inlines.Count != 0)
								{
									description.Inlines.Add("\n");
								}
								description.Inlines.Add(summary);

								//foreach (var entry in stuff)
								//{
								//    description += entry+ ": ";
								//    if (arguments.ContainsKey(entry) && arguments[entry]==index)
								//    {
								//        description += "___";
								//    }
								//    if (arg.ContainsKey(entry))
								//    {
								//        description += arg[entry].GetString();
								//    }
								//    else
								//    {
								//        description += entry;
								//    }
								//    if (arguments.ContainsKey(entry) && arguments[entry] == index)
								//    {
								//        description += "___";
								//    }
								//    description += "\n";
								//}
								//description = description.Trim();
							}
						}
						catch (Exception e)
						{
						}
						if (description.Text.Trim() == "")
						{
							return null;
						}
						return description;
					}
				}
			}

			public ImageSource Image
			{
				get
				{
					return null;
					if (value is Method)
					{
						return method;
					}
					else if (value is PropertyMap)
					{
						return properties;
					}
					else if (value is EventMap)
					{
						return events;
					}
					else if (value is TypeMap)
					{
						return classes;
					}
					else if (value is AssemblyMap)
					{
						return assembly;
					}
					else if(value.ContainsKey(CodeKeys.Program))
					{
						return method;
					}
					return null;
				}
			}

			public string Text
			{
				get
				{
					return this.key.ToString();
				}
			}
			public static BitmapImage method = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Method.png"));
			public static BitmapImage properties = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Properties.png"));
			public static BitmapImage events = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Event.png"));
			public static BitmapImage classes = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Class.png"));
			public static BitmapImage assembly = new BitmapImage(new Uri("pack://application:,,,/images/VSObject_Assembly.png"));
		}
		private void DisplayIntellisense(Meta.Expression e, bool all)
		{
			intellisense = new CompletionWindow(this.TextArea) { CloseAutomatically = true, CloseWhenCaretAtBeginning = true };
			intellisense.Resources.Add(SystemColors.HighlightBrushKey, Brushes.LightGray);
			intellisense.CompletionList.ListBox.FontFamily = new FontFamily("Tahoma");
			intellisense.CompletionList.ListBox.FontSize ++;
			intellisense.Closed += delegate
			{
				intellisense = null;
			};

			int startPosition;
			if (selectionStart != null)
			{
				startPosition = (int)selectionStart;
			}
			else
			{
				startPosition = SelectionStart;
			}
			//int startPosition = SelectionStart;
			Interpreter.stopStatements.Clear();
			if (e.Statement != null)
			{
				Interpreter.stopStatements.Add(e.Statement);
			}
			if (e.Parent != null && e.Parent.Statement != null)
			{
				Interpreter.stopStatements.Add(e.Parent.Statement);
			}
			Map s;
			if (e is Program)
			{
				s = Simulate(e);
			}
			else
			{

				if (e.Children.Count() == 1)
				{
					e = e.Children.First();
				}
				s = Simulate(e);
				//s = Simulate(e.Children.First());
			}

			//Editor.intellisenseItems = new List<Item>();
			List<KeyValuePair<Map, Map>> keys = new List<KeyValuePair<Map, Map>>();
			if (s != null)
			{
				Map currentMap = s;
				while (true)
				{
					foreach (Map m in currentMap.Keys)
					{
						keys.Add(new KeyValuePair<Map, Map>(m, currentMap[m]));
					}
					if (all)
					{
						currentMap = currentMap.Scope;
					}
					else
					{
						break;
					}
					if (currentMap == null)
					{
						break;
					}
				}
			}
			keys.Sort(delegate(KeyValuePair<Map, Map> a, KeyValuePair<Map, Map> b)
			{
				return a.Key.ToString().CompareTo(b.Key.ToString());
			});

			int maxLength = 0;
			foreach (var x in keys)
			{
				int length = x.Key.ToString().Length;
				if (length > maxLength)
				{
					maxLength = length;
				}
			}
			foreach (var z in keys)
			{
				intellisense.CompletionList.CompletionData.Add(new Completion(z.Key,z.Value));
			}
			if (keys.Count != 0)
			{
				this.intellisense.StartOffset = startPosition;
				this.intellisense.Show();
			}
			Meta.Expression.sources.Clear();
		}
        public void StopInteractiveSearch()
        {
			Editor.editor.Cursor = Cursors.IBeam;
			Mouse.OverrideCursor = Editor.editor.Cursor;
			interactiveSearch.text = "";
			interactiveSearch.Active = false;
        }
        public void StartInteractiveSearch(int forward)
        {
			if (interactiveSearch.Active && interactiveSearch.text == "")
			{
				interactiveSearch.text = interactiveSearch.oldText;
			}		

			interactiveSearch.Active = true;
			if (forward == 1)
			{
				Editor.editor.Cursor = Cursors.ScrollS;
			}
			else
			{
				Editor.editor.Cursor = Cursors.ScrollN;
			}
			Mouse.OverrideCursor = Editor.editor.Cursor;
			interactiveSearch.Find(forward);
        }
		public InteractiveSearch interactiveSearch;
		public void PressKey(KeyEventArgs asdf)
		{
			var xConverter = new KeyConverter();
			char xChar = xConverter.ConvertToString(asdf.Key)[0];

			TextComposition composition = new TextComposition(InputManager.Current,this, xChar.ToString().ToLower());
			TextCompositionEventArgs e = new TextCompositionEventArgs(Keyboard.PrimaryDevice, composition);
			e.RoutedEvent = UIElement.TextInputEvent;

			this.RaiseEvent(e);
		}
		public Map Simulate(Meta.Expression e)
		{
			Map.arguments = new List<Map>();
			Map context;
			if (e.Statement != null)
			{
				Interpreter.stopStatements.Add(e.Statement);
			}
			// TODO: make sure parent is always set
			if (e.Parent == null)
			{
				//DirectoryMap directory = new DirectoryMap(System.IO.Path.GetDirectoryName(page.fileName));
				//directory.Scope = Meta.Maps.Repository.Versions.versions;
				//context = directory;
				context = Meta.Versions.versions;
			}
			else
			{
				Meta.Expression parent = e.Parent;
				while (parent != null && !(parent is Program))
				{
					if (parent.Statement != null)
					{
						Interpreter.stopStatements.Add(e.Statement);
						// TODO: should not be necessary
						parent = parent.Statement.Parent;
					}
					else
					{
						parent = parent.Parent;
					}
				}
				// TODO: make sure parent is always set
				if (parent == null)
				{
					context = EmptyMap.Empty;
				}
				else
				{
					context = Simulate(parent);
				}
			}
			return e.Evaluate(ref context);
		}
	}
	public class IndentColorizer : DocumentColorizingTransformer, IWeakEventListener
	{
		readonly TextView textView;
		readonly HighlightingRuleSet ruleSet;
		DocumentHighlighter highlighter;
		bool isInTextView;

		/// <summary>
		/// Creates a new HighlightingColorizer instance.
		/// </summary>
		/// <param name="textView">The text view for which the highlighting should be provided.</param>
		/// <param name="ruleSet">The root highlighting rule set.</param>
		public IndentColorizer(TextView textView)
		{
			if (textView == null)
				throw new ArgumentNullException("textView");
			//if (ruleSet == null)
			//    throw new ArgumentNullException("ruleSet");
			this.textView = textView;
			//this.ruleSet = ruleSet;
			TextViewWeakEventManager.DocumentChanged.AddListener(textView, this);
			OnDocumentChanged();
		}

		/// <inheritdoc/>
		protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
		{
			if (managerType == typeof(TextViewWeakEventManager.DocumentChanged))
			{
				OnDocumentChanged();
				return true;
			}
			return false;
		}

		bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
		{
			return ReceiveWeakEvent(managerType, sender, e);
		}

		void OnDocumentChanged()
		{
			if (highlighter != null && isInTextView)
			{
				textView.Services.RemoveService(typeof(DocumentHighlighter));
			}

			//TextDocument document = textView.Document;
			//if (document != null)
			//    highlighter = new TextViewDocumentHighlighter(this, document, ruleSet);
			//else
			//    highlighter = null;

			if (highlighter != null && isInTextView)
			{
				textView.Services.AddService(typeof(DocumentHighlighter), highlighter);
			}
		}

		/// <inheritdoc/>
		protected override void OnAddToTextView(TextView textView)
		{
			base.OnAddToTextView(textView);
			isInTextView = true;
			if (highlighter != null)
			{
				textView.Services.AddService(typeof(DocumentHighlighter), highlighter);
			}
		}

		/// <inheritdoc/>
		protected override void OnRemoveFromTextView(TextView textView)
		{
			base.OnRemoveFromTextView(textView);
			isInTextView = false;
			if (highlighter != null)
			{
				textView.Services.RemoveService(typeof(DocumentHighlighter));
			}
		}


		int currentLineEndOffset;


		public static Brush[] brushes = new Brush[]{
			new SolidColorBrush(Color.FromRgb(255, 215, 215)),
			new SolidColorBrush(Color.FromRgb(255, 160, 160))
		};
		/// <inheritdoc/>
		protected override void ColorizeLine(DocumentLine line)
		{
			if (CurrentContext.TextView != textView)
				throw new InvalidOperationException("Wrong TextView");


			
			string text=this.CurrentContext.Document.Text;
			if(text=="")
			{
				return;
			}
			//ChangeLinePart(line.Offset,line.EndOffset,a=>ApplyColorToElement(a,new HighlightingColor(){Foreground=new HighlightingBrush()
			

			//for (int i = line.Offset; i < line.EndOffset; i++)
			//{
			//    Meta.Expression e=Editor.CurrentPage.textBox.GetCorrectExpression(new List<Meta.Expression>(new Meta.Expression[] {  m.GetExpression()}),i);
			//    int strength = 0;
			//    while (e != null)
			//    {
			//        e = e.Parent;
			//        strength++;
			//    }
			//}





			int begin = line.Offset;
			int oldStrength = 0;
			for (int i = line.Offset; i < text.Length; i++)
				//for (int i = line.Offset; i <= line.EndOffset; i++)
			{
				//if (i == 23)
				//{
				//}
				if (line.LineNumber == 233)
				{
				}
				//string s = line.Document.Text.Substring(0, i);
				//var starts = s.Split('{', '(', '[');
				//var ends = s.Split('}', ')', ']');




				if (Editor.CurrentPage.textBox.Parsed == null)
				{
					return;
				}
				Meta.Expression e = Editor.CurrentPage.textBox.GetCorrectExpression(new List<Meta.Expression>(new Meta.Expression[] { Editor.CurrentPage.textBox.Parsed}), i);
				int strength = 0;
				while (e != null)
				{
					e = e.Parent;
					strength++;
				}

				//int strength = (starts.Count() - ends.Count());
				//int start;


				//if ("{([".Contains(line.Document.Text[i]))
				//{
				//    start = i-1;
				//}
				//else
				//{
				//    start = i;
				//}
				int end = i;
				// TODO: ??
				//if (i < line.Document.Text.Length && "{([".Contains(line.Document.Text[i]))
				////if (i + 1 < line.Document.Text.Length && "{([".Contains(line.Document.Text[i + 1]))
				//{
				//    strength++;
				//    //end = i;
				//}
				//else
				//{
				//switch (line.Document.Text[i])
				//{
				//    //case '\t':
				//        //case ' ':
				//        //break;

				//    default:
				//var brush=brushes[strength%2];
				//if (!"{[()]}\".|=".Contains(line.Document.Text[i]))
				//{
				if (strength != oldStrength )// || "{[()]}\".|=\t".Contains(line.Document.Text[i]))
				//if (strength != oldStrength || "{[()]}\".|=\t".Contains(line.Document.Text[i]))
				{
					//var brush = new SolidColorBrush(HlsValueConverter.HlsToRgb(new HlsValueConverter.HlsColor() { A = 1, H = (60+strength*30)%360, L = 0.7, S = 0.5}));
					//var brush = new SolidColorBrush(HlsValueConverter.HlsToRgb(new HlsValueConverter.HlsColor() { A = 0.5, H = 20, L = 0.8, S = 0.2 * (double)(strength % 5) }));
					//var brush = new SolidColorBrush(HlsValueConverter.HlsToRgb(new HlsValueConverter.HlsColor() { A = 0.5, H = 20, L = 0.8, S = 0.2 * (double)(strength % 5) }));
					//var brush = new SolidColorBrush(HlsValueConverter.HlsToRgb(new HlsValueConverter.HlsColor() { A = 0.5, H = (strength * 20) % 200, L = 0.5, S = 0.5 }));
					var brush = new SolidColorBrush(HlsValueConverter.HlsToRgb(new HlsValueConverter.HlsColor() { A = 0.5, H = (oldStrength * 20) % 360, L = 0.5, S = 1 }));
					//var brush = new SolidColorBrush(HlsValueConverter.HlsToRgb(new HlsValueConverter.HlsColor() { A = 0.5, H = (strength * 20) % 180, L = 0.5, S = 1 }));
					//var brush = new SolidColorBrush(Color.FromRgb(255, (byte)(strength * (-30) + 255), (byte)(strength * (-30) + 255)));// Brushes.Red;
					//var brush = new SolidColorBrush(Color.FromRgb(255, (byte)(strength * (-30) + 255), (byte)(strength * (-30) + 255)));// Brushes.Red;
					//var brush = new SolidColorBrush(Color.FromRgb((byte)(strength * 20 + 100), (byte)(strength * 20 + 20), (byte)(strength * 20 + 20)));// Brushes.Red;
					ChangeLinePart(begin, Math.Min(line.EndOffset,i), a => a.TextRunProperties.SetBackgroundBrush(brush));// ApplyColorToElement(a,new HighlightingColor(){Foreground=new HighlightingBrush
					//ChangeLinePart(begin, i + 1, a => a.TextRunProperties.SetBackgroundBrush(brush));// ApplyColorToElement(a,new HighlightingColor(){Foreground=new HighlightingBrush
					//ChangeLinePart(i, i + 1, a => a.TextRunProperties.SetBackgroundBrush(brush));// ApplyColorToElement(a,new HighlightingColor(){Foreground=new HighlightingBrush
					oldStrength = strength;
					//while (line.Document.Text[i] == '\t' && i < line.Document.Text.Length)
					//{
					//    i++;
					//}

					begin = i;


					if (i > line.EndOffset)
					{
						return;
					}
					//begin = i + 1;
					//begin = i + 1;

					//if ("{[()]}\".|=".Contains(line.Document.Text[i]))
					//{
					//    i++;
					//}
				}
				else
				{
					//begin = i;
				}
				//}
				//        break;
				//}

				//}
				//else
				//{
				//    end = i - 1;
				//}
			}
			//this.CurrentElements.Add(
			//    new InlineObjectElement(
			//        1,
			//        new Ellipse() { Width = 10, Height = 10, Fill = Brushes.Red, Stroke = Brushes.Green }
			//    ) { TextRunProperties = new VisualLineElementTextRunProperties(this.CurrentContext.GlobalTextRunProperties) }
			//);
			//this.CurrentElements.Add(
			//    new FormattedTextElement(
			//        new FormattedText(
			//            "hello!",
			//            CultureInfo.InvariantCulture,
			//            FlowDirection.LeftToRight,
			//            new Typeface(Settings.Font),
			//            Editor.fontSize,
			//            Brushes.Yellow
			//        ),
			//        "hello!".Length
			//    )
			//    {
			//        TextRunProperties=new VisualLineElementTextRunProperties(this.CurrentContext.GlobalTextRunProperties)
			//    }
			//);

			//var starts = line.Document.Text.Substring(0, line.Offset).Split('{');
			//var ends = line.Document.Text.Substring(0, line.Offset).Split('}');
			//int strength = (starts.Count() - ends.Count());
			//var brush = new SolidColorBrush(Color.FromRgb((byte)(strength * 30 + 100), (byte)(strength * 30), (byte)(strength * 30)));// Brushes.Red;
			//ChangeLinePart(line.Offset, line.EndOffset, a => a.TextRunProperties.SetBackgroundBrush(brush));// ApplyColorToElement(a,new HighlightingColor(){Foreground=new HighlightingBrush());

			//var starts=line.Document.Text.Substring(0, line.Offset).Split('{');
			//var ends = line.Document.Text.Substring(0, line.Offset).Split('}');
			//int strength=(starts.Count()-ends.Count());
			//var brush = new SolidColorBrush(Color.FromRgb((byte)(strength * 30 + 100), (byte)(strength * 30), (byte)(strength * 30)));// Brushes.Red;
			//ChangeLinePart(line.Offset,line.EndOffset,a=>a.TextRunProperties.SetBackgroundBrush(brush));// ApplyColorToElement(a,new HighlightingColor(){Foreground=new HighlightingBrush());
			//element.TextRunProperties.SetForegroundBrush(b);
			//if (highlighter != null)
			//{

			//    currentLineEndOffset = line.Offset + line.TotalLength;
			//    HighlightedLine hl = highlighter.HighlightLine(line);
			//    foreach (HighlightedSection section in hl.Sections)
			//    {
			//        ChangeLinePart(section.Offset, section.Offset + section.Length,
			//                       visualLineElement => ApplyColorToElement(visualLineElement, section.Color));
			//    }
			//}
		}

		/// <summary>
		/// Applies a highlighting color to a visual line element.
		/// </summary>
		protected virtual void ApplyColorToElement(VisualLineElement element, HighlightingColor color)
		{
			if (color.Foreground != null)
			{
				Brush b = color.Foreground.GetBrush(CurrentContext);
				if (b != null)
					element.TextRunProperties.SetForegroundBrush(b);
			}
			if (color.FontStyle != null || color.FontWeight != null)
			{
				Typeface tf = element.TextRunProperties.Typeface;
				element.TextRunProperties.SetTypeface(new Typeface(
					tf.FontFamily,
					color.FontStyle ?? tf.Style,
					color.FontWeight ?? tf.Weight,
					tf.Stretch
				));
			}
		}

		//sealed class TextViewDocumentHighlighter : DocumentHighlighter
		//{
		//    HighlightingColorizer colorizer;

		//    public TextViewDocumentHighlighter(HighlightingColorizer colorizer, TextDocument document, HighlightingRuleSet baseRuleSet)
		//        : base(document, baseRuleSet)
		//    {
		//        Debug.Assert(colorizer != null);
		//        this.colorizer = colorizer;
		//    }

		//    protected override void OnHighlightStateChanged(DocumentLine line, int lineNumber)
		//    {
		//        base.OnHighlightStateChanged(line, lineNumber);
		//        if (colorizer.currentLineEndOffset >= 0)
		//        {
		//            // Do not use colorizer.CurrentContext - the colorizer might not be the only
		//            // class calling DocumentHighlighter.HighlightLine, the the context might be null.
		//            int length = this.Document.TextLength - colorizer.currentLineEndOffset;
		//            if (length != 0)
		//            {
		//                // don't redraw if length == 0: at the end of the document, this would cause
		//                // the last line which was already constructed to be redrawn ->
		//                // we would get an exception due to disposing the line that was already constructed
		//                colorizer.textView.Redraw(colorizer.currentLineEndOffset, length, DispatcherPriority.Normal);
		//            }
		//            colorizer.currentLineEndOffset = -1;
		//        }
		//    }
		//}
	}
	public partial class Editor : System.Windows.Window
	{
		public static Editor.Page CurrentPage
		{
			get
			{
				return (Page)editor.tabs.SelectedItem;
			}
		}
		public static Map debuggingContext;
		//public static ListView errorList;

		//public static Grid grid = new Grid();
		public class DocumentationKeys
		{
			public static readonly Map Documentation="documentation";
			public static readonly Map Summary= "summary";
			public static readonly Map Arguments = "arguments";
		}
		public class Tip : Popup
		{
		}
		public static Brush backgroundBrush = Brushes.White;
		public class Page : TabItem
		{
			//public TextBlock label = new TextBlock()
			//{
			//    FontFamily = new FontFamily("Calibri"),
			//    FontSize = 13
			//};

			public bool undoHistory = false;

			public string fileName = null;
			public Box textBox;
			//public Canvas canvas = new Canvas();
			private bool _changes = false;

			public void SetHeader(string text)
			{
				this.Header=text;
			}
			// TODO: remove this?
			public void Highlight(Meta.Expression expression)
			{
				Select select=expression as Select;
				Search search = expression as Search;
				Call call=expression as Call;
				Literal literal = expression as Literal;
				Program program = expression as Program;
				if (select != null)
				{
					Literal l= select.subs[select.subs.Count - 1] as Literal;
					if (l != null)
					{
						DoHighlight(l, TextElement.FontWeightProperty,FontWeights.Bold);
					}
				}
				else if(search!=null && search.expression is Literal && !(search.Parent is Select))
				{
					DoHighlight(search.expression, TextElement.FontWeightProperty, FontWeights.Bold);
					return;
				}
				else if (call != null)
				{
					DoHighlight(call, TextElement.BackgroundProperty, Brushes.Yellow);
				}
				else if (literal != null && !(literal.Parent is Search) && !(literal.Parent is Select))
				{
					DoHighlight(literal, TextElement.BackgroundProperty, Brushes.LightGreen);
				}
				//foreach (Meta.Expression e in expression.Children)
				//{
				//    Highlight(e);
				//}
			}

			private void DoHighlight(Meta.Expression a,DependencyProperty property,object value)
			{
				//Dispatcher.Invoke(new Func<int>(delegate
				//{
				//    TextPointer start=GetPosition(a.Source.Start);
				//    TextPointer end = GetPosition(a.Source.End);
				//    if (start != null && end != null)
				//    {
				//        TextRange range = new TextRange(start, end);
				//        range.ApplyPropertyValue(property, value);
				//    }
				//    return 0;
				//}));
			}
			public bool Compile(string text, bool automatic,out Map map,out Parser p)
			{
				Interpreter.profiling = false;
				foreach (Dictionary<Parser.ParserState, Parser.CachedResult> cached in Parser.allCached)
				{
					cached.Clear();
				}
				Parser parser = new Parser(text, fileName);
				p = parser;
				map = null;
				bool matched = Parser.File.Match(parser, ref map);
				Dispatcher.Invoke(DispatcherPriority.Normal, new Func<bool>(delegate
				{
					foreach (Rectangle line in errors)
					{
						//canvas.Children.Remove(line);
					}
					errors.Clear();
					return true;
				}));
				foreach (Error error in parser.state.Errors)
				{
					Dispatcher.Invoke(DispatcherPriority.Normal, new Func<bool>(delegate
					{
						//MakeLine(error.State, error.Text);
						return true;
					}));
				}
				if (parser.state.index != text.Length)
				{
					Dispatcher.Invoke(DispatcherPriority.Normal, new Func<bool>(delegate
					{
						//MakeLine(parser.state, "Expected end of file.");
						return true;
					}));
					//return false;
				}
				if(!automatic)
				{
					if(parser.state.Errors.Length != 0)
					{
						Dispatcher.Invoke(DispatcherPriority.Normal, new Func<bool>(delegate
						{
							editor.errorList.Visibility = Visibility.Visible;
							editor.errorList.Items.Clear();
							//errorList = parser.state.Errors;
							//error
							//errorList.SelectionChanged += new SelectionChangedEventHandler(errorList_SelectionChanged);
							
							foreach (Error error in parser.state.Errors)
							{
								ListViewItem item = new ListViewItem();
								//item.Focusable = false;
								//item.Content = error;
								Error e = error;
								//item.GotFocus += new RoutedEventHandler(item_GotFocus);
								//item.MouseDoubleClick += new MouseButtonEventHandler(item_MouseDoubleClick);
								//item.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(item_GotKeyboardFocus);
								item.Content = error.Text + " " +error.Source.ToString();
								item.DataContext = e;
								item.Selected += delegate
								{
									//Dispatcher.Invoke(new Action(delegate
									//{
									//    textBox.SelectionStart = e.Source.Index;
									//    //item.IsSelected = false;
									//    //TextPointer pos = textBox.GetPosition(error.Source.Line, error.Source.Column);
									//    //TextPointer pos = textBox.GetPosition(error.Source.Line, error.Source.Column);
									//    //textBox.Selection.Select(pos, pos);
									//    //errorList.SelectedItem = null;


									//DependencyObject focusScope = FocusManager.GetFocusScope(errorList);
									////if (FocusManager.GetFocusedElement(focusScope) == null)
									////{
									//FocusManager.SetFocusedElement(focusScope, textBox);
									//var asdf = FocusManager.GetFocusedElement(focusScope);
									////}
									//Keyboard.Focus(textBox);

									//    //bool x=textBox.Focus();
									//    //var a=Keyboard.Focus(textBox);
									//    //textBox.ScrollToLine(e.Source.Line);
										
									//    //Console.WriteLine(x);
									//    //tabs.Focus();
									//    //Keyboard.Focus(tabs);
									//    //textBox.Focus();
									//    //object x = Keyboard.Focus(textBox);
									//    //Console.WriteLine("hi");
									//    //return 0;

									//}
									//));
								};
								editor.errorList.Items.Add(item);
								//errorList.Items.Add(error);
							}
							return true;
						}));
					}
					else
					{
						HideErrors();
					}
				}
				return true;
			}
			public bool Close()
			{
				if (changes)
				{
					switch (MessageBox.Show("Save changes to "+System.IO.Path.GetFileName(fileName)+"?", ProgramName, MessageBoxButton.YesNoCancel))
					{
						case MessageBoxResult.Yes:
							Save();
							break;
						case MessageBoxResult.No:
							break;
						case MessageBoxResult.Cancel:
							return false;
					}
				}
				//pages.Remove(this);
				editor.tabs.Items.Remove(this);
				//ApplicationCommands.CancelPrint.Text
				return true;
			}
			public Page()
			{
				this.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
				Style style = new Style(typeof(Paragraph));
				//style.Setters.Add(new Setter(Paragraph.TextIndentProperty, 100.0));
				style.Setters.Add(new Setter(Paragraph.MarginProperty, new Thickness(5, 0, 0, 0)));
				//this.Background = backgroundBrush;
				//this.Foreground = Brushes.White;
				this.Resources.Add(typeof(Paragraph), style);
				//Editor.grid.Children.Add(intellisense);
				Thread debugThread = null;

				VisualBrush circle = new VisualBrush(new Ellipse()
				{
					Fill = Brushes.Red,
					Width = 100,
					Height = 20,
					Stroke = Brushes.Red,
					HorizontalAlignment = HorizontalAlignment.Center
				});
				this.CommandBindings.AddRange(new CommandBinding[] {
				//    new CommandBinding(EditorCommands.SetBreakpoint,delegate
				//    {
				//        TextRange range=new TextRange(
				//            textBox.CaretPosition,
				//            textBox.CaretPosition.GetNextInsertionPosition(LogicalDirection.Forward)
				//        );
				//        Brush brush = (Brush)range.GetPropertyValue(TextElement.BackgroundProperty);
				//        Brush newBrush;
				//        if (brush != null && brush == circle)
				//        {
				//            newBrush = Brushes.White;
				//        }
				//        else
				//        {
				//            newBrush = circle;
				//        }
				//        range.ApplyPropertyValue(
				//            TextElement.BackgroundProperty,
				//            newBrush
				//        );
				//    }),
				//    new CommandBinding(
				//        ApplicationCommands.Find,
				//        delegate
				//        {
				//            findAndReplace.Owner = editor;
				//            findAndReplace.Show();
				//        }
				//    ),
				    new CommandBinding(ApplicationCommands.Save, delegate { Save(false); }),
					new CommandBinding(ApplicationCommands.SaveAs, delegate { Save(true); }),
				    new CommandBinding(EditorCommands.StartWithoutDebugging,delegate {
				        Save();
				        if (Compile(false))
				        {
				            Process.Start(
								//@"C:\meta 0.3\bin\x86\Release\Meta.exe",
								System.IO.Path.Combine(@"C:\Projects\Meta\Meta Executable\bin\Debug", "Meta.exe"),
								//System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Meta.exe"),
								"\"" + fileName + "\""
				            );
				        }
				    }),
				//    new CommandBinding(EditorCommands.StopDebugging,delegate {
				//        if (debugThread != null)
				//        {
				//            debugThread.Abort();
				//        }
				//    }),
				//    new CommandBinding(EditorCommands.StartDebugging, delegate
				//    {
				//        if (debugThread != null)
				//        {
				//            debugThread.Resume();
				//        }
				//        else
				//        {
				//            watch1.Visibility = Visibility.Visible;
				//            Interpreter.breakpoints.Clear();
				//            TextPointer position = textBox.Document.ContentStart;
				//            while (position != null)
				//            {
				//                TextPointer next = position.GetNextInsertionPosition(LogicalDirection.Forward);
				//                if (next != null)
				//                {
				//                    TextRange range = new TextRange(position, next);
				//                    SolidColorBrush brush = (SolidColorBrush)range.GetPropertyValue(TextElement.BackgroundProperty);
				//                    if (brush != null && brush.Color == Colors.Red)
				//                    {
				//                        Interpreter.breakpoints.Add(new Source(textBox.GetLine(position), textBox.GetColumn(position),0, fileName));
				//                    }
				//                }
				//                position = next;
				//            }
				//            debugThread = new Thread(new ThreadStart(delegate()
				//            {
				//                Interpreter.Run(fileName, Meta.Maps.EmptyMap.Empty);
				//            }));
				//            debugThread.Start();
				//        }
				//    }),
				//    new CommandBinding(
				//        EditorCommands.Combo,
				//        delegate
				//        {
				//            this.textBox.keyCombo = true;
				//        }
				//    ),
				//    new CommandBinding(EditorCommands.CancelCombo,delegate
				//    {
				//        this.textBox.keyCombo = false;
				//    }),
				    new CommandBinding(EditorCommands.GoToMatchingBrace,delegate
				    {
				        int start = FindMatchingBrace();
				        if (start >= 0)
				        {
				            textBox.Select(start, 0);
							TextLocation location=textBox.Document.GetLocation(textBox.SelectionStart);
							textBox.ScrollTo(location.Line,location.Column);
				        }
				    }),
				    new CommandBinding(EditorCommands.SelectToMatchingBrace, delegate
				    {
				        int end = FindMatchingBrace();
				        if (end != -1)
				        {
							int start=textBox.SelectionStart;
							//if(end < start)
							//{
							//    int endCopy;
							//    end=start;
							//    start=endCopy;
							//}
				            textBox.Select(Math.Min(start,end), Math.Abs(start-end));// textBox.SelectionStart, start-textBox.SelectionStart);
				        }
				    }),
					//new CommandBinding(ApplicationCommands.Print, delegate
					//{
					//    //TextRange sourceDocument = new TextRange(textBox.Document.ContentStart, textBox.Document.ContentEnd);
					//    MemoryStream stream = new MemoryStream();
					//    sourceDocument.Save(stream, DataFormats.Xaml);
					//    FlowDocument flowDocumentCopy = new FlowDocument();
					//    TextRange copyDocumentRange = new TextRange(flowDocumentCopy.ContentStart, flowDocumentCopy.ContentEnd);
					//    copyDocumentRange.Load(stream, DataFormats.Xaml);
					//    PrintDocumentImageableArea ia = null;
					//    XpsDocumentWriter docWriter = PrintQueue.CreateXpsDocumentWriter(ref ia);
					//    if (docWriter != null && ia != null)
					//    {
					//        DocumentPaginator paginator = ((IDocumentPaginatorSource)flowDocumentCopy).DocumentPaginator;
					//        paginator.PageSize = new Size(ia.MediaSizeWidth, ia.MediaSizeHeight);
					//        Thickness pagePadding = flowDocumentCopy.PagePadding;
					//        flowDocumentCopy.PagePadding = new Thickness(
					//                Math.Max(ia.OriginWidth, pagePadding.Left),
					//                Math.Max(ia.OriginHeight, pagePadding.Top),
					//                Math.Max(ia.MediaSizeWidth - (ia.OriginWidth + ia.ExtentWidth), pagePadding.Right),
					//                Math.Max(ia.MediaSizeHeight - (ia.OriginHeight + ia.ExtentHeight), pagePadding.Bottom));
					//        flowDocumentCopy.ColumnWidth = double.PositiveInfinity;
					//        docWriter.Write(paginator);
					//    }
					//}),
				    new CommandBinding(EditorCommands.GoToLine,delegate
				    {
				        StackPanel panel = new StackPanel();
				        TextBox box = new TextBox()
				        {
				            Text = (textBox.Document.GetLineByOffset(textBox.SelectionStart).LineNumber).ToString(),
				            AcceptsReturn = false,
							//Foreground=Brushes.White,
							//Background=backgroundBrush
				        };
				        Button button = new Button(){
				            Content = "OK",
							//Foreground=Brushes.White,
							//Background=backgroundBrush
				        };
				        panel.Children.Add(box);
				        panel.Children.Add(button);
				        Window window = new Window()
				        {
				            Content=panel,
				            Title = "Go to line",
				            ShowInTaskbar = false,
				            Width = 40,
				            Height = 70,
							//Background=backgroundBrush,
							//Foreground=Brushes.White
				        };
				        box.Select(0, box.Text.Length);
				        box.Focus();
				        Func<int> go = delegate
				        {
				            int line;
				            if (int.TryParse(box.Text, out line))
				            {
				                if (line < textBox.LineCount)
				                {
				                    int start=textBox.Document.GetOffset(line,1);
				                    textBox.Select(start,0);									
				                    window.Close();
									textBox.ScrollToCursor();									
				                }
				            }
				            return 0;
				        };
				        window.KeyDown += delegate(object sender, KeyEventArgs e)
				        {
				            if (e.Key == Key.Enter)
				            {
				                go();
				            }
				            else if (e.Key == Key.Escape)
				            {
				                window.Close();
				            }
				        };
				        button.Click += delegate
				        {
				            go();
				        };
				        window.ShowDialog();
				    })
				});

				textBox = new Box(this)
				{
					//AcceptsReturn = true,
					FontSize = fontSize,
					FontFamily = font,
					//Background = backgroundBrush,
					//Background = new ImageBrush(new BitmapImage(new Uri("pack://application:,,,/images/untitled.bmp"))) {Stretch=Stretch.None,TileMode=TileMode.Tile,ViewportUnits=BrushMappingMode.Absolute,Viewport=new Rect(0,0,1000,1000) },
					//Foreground = Brushes.White,
				};
				//textBox.SetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Visible);
				//textBox.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Visible);

				findAndReplace=new Replace();

				textBox.PreviewKeyDown += new KeyEventHandler(delegate(object sender, KeyEventArgs e)
				{
					//if (e.Key == Key.Down)
					//{
					//    if (Intellisense)
					//    {
					//        EditingCommands.MoveDownByLine.Execute(null, intellisense.listbox);
					//        e.Handled = true;
					//    }
					//}
					//if (e.Key == Key.Up)
					//{
					//    if (Intellisense)
					//    {
					//        EditingCommands.MoveUpByLine.Execute(null, intellisense.listbox);
					//        e.Handled = true;
					//    }
					//}
					
					//if (e.Key == Key.K)
					//{
					//    if (e.KeyboardDevice.Modifiers == ModifierKeys.Control)
					//    {
					//        if (textBox.IntellisenseVisible())
					//        {
					//            EditingCommands.MoveDownByLine.Execute(null, textBox.intellisense);
					//            e.Handled = true;
					//        }
					//    }
					//}
					//if (e.Key == Key.)
					//{
						//if (e.KeyboardDevice.Modifiers == ModifierKeys.Alt && e.Key!=Key.System)
						//{
						//    if (textBox.IntellisenseVisible())
						//    {
						//        EditingCommands.MoveUpByLine.Execute(null, textBox.intellisense);
						//        e.Handled = true;
						//    }
						//}
					//}
					if (e.Key == Key.PageDown)
					{
						if (textBox.IntellisenseVisible())
						{
							EditingCommands.MoveDownByPage.Execute(null, textBox.intellisense);
							e.Handled = true;
						}
					}
					if (e.Key == Key.PageUp)
					{
						if (textBox.IntellisenseVisible())
						{
							EditingCommands.MoveUpByPage.Execute(null, textBox.intellisense);
							e.Handled = true;
						}
					}
				});
				bool changing = false;
				Random random = new Random();

				string currentText = "";
				// TODO: get debugging to work
				Meta.Expression.OnBreakPoint += new Meta.Expression.BreakPointEvent(delegate(Meta.Expression expression, Map context)
				{
					//expression.Source
					debuggingContext=context;

					Dispatcher.Invoke(DispatcherPriority.Normal, new Func<bool>(delegate
					{
						editor.watch1.Visibility = Visibility.Visible;
						//watch1.context = context;
						//foreach (var s in Meta.Expression.sources)
						//{
						//    foreach (var x in s.Value)
						//    {
						//        if (x is Search)
						//        {
						//            TreeView view = new TreeView()
						//            {
						//                Background = Brushes.Yellow
						//            };
						//            TreeViewItem item=new TreeViewItem();
						//            item.Items.Add("hi");
						//            item.Items.Add("hello");
						//            item.Header = "a";
						//            item.IsExpanded = true;
						//            view.Items.Add(item);

						//            //textBox.Document.Blocks.First().child
						//            Paragraph p = new Paragraph();
						//            p.Inlines.Add(view);
						//            this.textBox.Document.Blocks.InsertAfter(
						//                textBox.Document.Blocks.First(),
						//                //textBox.CaretPosition.Parent,
						//                p
						//            );
						//            break;
						//        }
						//    }
						//}
						return true;
					}));
					debugThread.Suspend();
				});

				DispatcherTimer timer = new DispatcherTimer();
				timer.Interval = new TimeSpan(0, 0, 1);
				List<TextRange> errors = new List<TextRange>();
				System.Windows.Shapes.Path path=new System.Windows.Shapes.Path()
				{
					Stroke=Brushes.Red,
					StrokeThickness=0.2,
				};
				textBox.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
				path.Data = new PathGeometry(new PathFigure[] {new PathFigure(new Point(0.1,1),new LineSegment[] { new LineSegment(new Point(1,0),true),new LineSegment(new Point(2,2),true),new LineSegment(new Point(3,1),true)},true)});// new Rect(0, 3, 3, 3)); ;//("M 0.1,1 C 1,0 2,2 3,1" Stroke="Red" StrokeThickness="0.2" />
				VisualBrush underline = new VisualBrush(path);
				
				//timer.Tick += delegate
				//{
				//    timer.Stop();
				//    try
				//    {
				//        if (!Intellisense)
				//        {
				//            string text = textBox.Text;
				//            Thread thread = new Thread(new ThreadStart(delegate
				//            {
				//                Map m;
				//                Parser p;
				//                Compile(text, true, out m, out p);

				//                Dispatcher.Invoke(new Func<int>(delegate
				//                {
				//                    foreach (TextRange error in errors)
				//                    {
				//                        error.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.White);
				//                    }
				//                    foreach (var error in p.state.Errors)
				//                    {
				//                        TextPointer pos = textBox.GetPosition(error.State.Line, error.State.Column);//, textBox.Document.ContentStart);
				//                        TextPointer next = pos.GetNextInsertionPosition(LogicalDirection.Forward);
				//                        if (next == null)
				//                        {
				//                            pos.GetNextInsertionPosition(LogicalDirection.Backward);
				//                        }
				//                        TextRange e = new TextRange(pos, next);
				//                        errors.Add(e);
				//                        e.ApplyPropertyValue(TextElement.BackgroundProperty, underline);
				//                    }
				//                    return 0;
				//                }), new object[] { });
				//            }));
				//            thread.Priority = ThreadPriority.Lowest;
				//            thread.Start();
				//        }
				//    }
				//    finally
				//    {
				//        timer.Interval = new TimeSpan(0, 0, 1);
				//        timer.Start();
				//    }
				//};
				//timer.Start();
				RoutedUICommand back = new RoutedUICommand();
				BindKey(back, Key.OemMinus, ModifierKeys.Control);
				//Border b = new Border() { ,BorderBrush=Brushes.Blue, VerticalAlignment = System.Windows.VerticalAlignment.Stretch, HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch };

				this.Content = textBox;
				//this.Background = Brushes.Red;
				textBox.PreviewKeyDown += delegate(object obj, KeyEventArgs e)
				{
					if (textBox.keyCombo)
					{
						if (e.KeyboardDevice.Modifiers == ModifierKeys.Control)
						{
							if (e.Key == Key.C)
							{
								EditorCommands.Comment.Execute(null, textBox);
								e.Handled = true;
								textBox.keyCombo = false;
								e.Handled = true;
							}
							else if (e.Key == Key.U)
							{
								EditorCommands.Uncomment.Execute(null, textBox);
								e.Handled = true;
								textBox.keyCombo = false;
								e.Handled = true;
							}
						}
					}
					if (e.Key == Key.I && e.KeyboardDevice.Modifiers == ModifierKeys.Control)
					{
						EditorCommands.InteractiveSearch.Execute(null, textBox);
						e.Handled = true;
					}
				};
				Brush background = new SolidColorBrush(Color.FromRgb(255, 255, 225));
				// TODO: make this work
				textBox.TextArea.SelectionChanged += delegate
				{
					textBox.UpdateStatus();
					//TextLocation location=textBox.Document.GetLocation(textBox.SelectionStart);
					//message.Content = "Line " + location.Line+ ", Col " + location.Column;
					//UpdateBraces();
					if (textBox.interactiveSearch.Active && !textBox.interactiveSearch.Searching)
					{
						textBox.StopInteractiveSearch();
					}
				};
				textBox.Options.EnableEmailHyperlinks = false;
				textBox.Options.EnableHyperlinks = false;
			}
			public static string GetSignature(Method method)
			{
				string text = "";
				if (method.method is MethodInfo)
				{
					text += GetTypeName(((MethodInfo)method.method).ReturnParameter.ParameterType) + " ";
				}
				else
				{
					text += ((ConstructorInfo)method.method).DeclaringType.Name + ".";
				}
				text += method.method.Name.Trim();
				text += "(" + string.Join(", ", method.method.GetParameters().Select(parameter => GetTypeName(parameter.ParameterType) + " " + parameter.Name).ToArray()) + ")";
				return text;
			}
			TextRange brace = null;
			TextRange brace2 = null;
			bool changingBraces = false;
			private void UpdateBraces()
			{
				//textBox.TextArea								
			//    if (!changingBraces)
			//    {
			//        changingBraces = true;
			//        if (brace != null)
			//        {
			//            brace.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.White);
			//            brace = null;
			//        }
			//        if (brace2 != null)
			//        {
			//            brace2.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.White);
			//            brace2 = null;
			//        }
			//        if (textBox.Text.Length != 0 && textBox.SelectionStart < textBox.Text.Length)
			//        {
			//            for (int diff = -1; diff < 1; diff++)
			//            {
			//                char c = textBox.Text[Math.Max(0, Math.Min(textBox.Text.Length, textBox.SelectionStart + diff))];
			//                if ((openBraces + closeBraces).IndexOf(c) != -1)
			//                {
			//                    TextPointer index = FindMatchingBrace();
			//                    if (index != null)
			//                    {
			//                        TextPointer next;
			//                        TextPointer next2;
			//                        if (diff == -1)
			//                        {
			//                            next = index.GetNextInsertionPosition(LogicalDirection.Forward);
			//                            next2 = textBox.Selection.Start.GetNextInsertionPosition(LogicalDirection.Backward);
			//                        }
			//                        else
			//                        {
			//                            next = index.GetNextInsertionPosition(LogicalDirection.Backward);
			//                            next2 = textBox.Selection.Start.GetNextInsertionPosition(LogicalDirection.Forward);
			//                        }
			//                        brace = new TextRange(index, next);
			//                        brace2 = new TextRange(textBox.Selection.Start, next2);
			//                        brace.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.LightGray);
			//                        brace2.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.LightGray);
			//                    }
			//                    break;
			//                }
			//            }
			//        }
			//        changingBraces = false;
			//    }
			}
			public static string GetTypeName(Type t)
			{
				if(t==typeof(void))
				{
					return "void";
				}
				else if(t==typeof(bool))
				{
					return "bool";
				}
				else if(t==typeof(char))
				{
					return "char";
				}
				else if(t==typeof(byte))
				{
					return "byte";
				}
				else if(t==typeof(short))
				{
					return "short";
				}
				else if(t==typeof(ushort))
				{
					return "ushort";
				}
				else if(t==typeof(int))
				{
					return "int";
				}
				else if(t==typeof(uint))
				{
					return "uint";
				}
				else if(t==typeof(long))
				{
					return "long";
				}
				else if(t==typeof(ulong))
				{
					return "ulong";
				}
				else if(t==typeof(float))
				{
					return "float";
				}
				else if(t==typeof(double))
				{
					return "double";
				}
				else if(t==typeof(uint))
				{
					return "uint";
				}
				else if(t==typeof(int))
				{
					return "int";
				}
				else if(t==typeof(object))
				{
					return "object";
				}
				else if(t==typeof(string))
				{
					return "string";
				}
				else 
				{
					return t.Name;
				}
			}
			public int FindMatchingBrace()
			{
				int position = textBox.SelectionStart;
				int direction;
				int index;
				char open;
				char close;


				if (position < textBox.Text.Length && (index = openBraces.IndexOf(open = textBox.Text[position])) != -1)
				{
					direction = 1;
					close = closeBraces[index];
				}
				else
				{
					position = position-1;
					if (position>textBox.Text.Length)
					{
						return -1;
					}
					if ((index = closeBraces.IndexOf(open = textBox.Text[position])) != -1)
					{
						direction = -1;
						close = openBraces[index];
					}
					else
					{
						return -1;
					}
				}
				if (index != -1)
				{
					return FindMatchingBrace(position, open, close, direction);
				}
				return -1;
			}
			private int FindMatchingBrace(int position,char open,char close,int direction)
			{
				int count = 1;
				while (true)
				{
					position = position+direction;
					if (position == -1)
					{
						return -1;
					}
					else if (position >= textBox.Text.Length)
					{
						return -1;
					}
					char c = textBox.Text[position];
					if (c == close)
					{
						count--;
					}
					else if (c == open)
					{
						count++;
					}
					if (count == 0)
					{
						if (direction == 1)
						{
							position++;
						}
						return position;
					}
				}
			}
			public void MassEdit(bool increase, string text)
			{
				int start = textBox.Document.GetOffset(textBox.Document.GetLineByOffset(textBox.SelectionStart).LineNumber, 1);// .GetLineStartPosition(0);
				int end = textBox.SelectionStart + textBox.SelectionLength;
				// TODO: fix this
				//textBox.Text = textBox.Text.Substring(0, start) + ("\r\n" + textBox.Text).Substring(start, end - start).Replace("\r\n", "\r\n" + text) + textBox.Text.Substring(end, textBox.Text.Length - end);
				//textBox.Text = textBox.Text.Substring(0, start) + ("\r\n" + textBox.Text).Substring(start, end - start).Replace("\r\n", "\r\n" + text) + textBox.Text.Substring(end, textBox.Text.Length - end);

				if (end > start + 2)
				{
					end -= 2;
				}
				while (start>0 && textBox.Text[start]!='\r')
				{
					start--;
				}
				while (end<textBox.Text.Length-1 && textBox.Text[end] != '\n')
				{
					end++;
				}
				// TODO: expand to full line
				string original=textBox.Text.Substring(start, end - start);
				string t;
				if (increase)
				{
					var lines=original.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
					int count=lines.Select(a=>a.TrimStart('\r','\n')).Select(a => a.Length - a.TrimStart('\t').Length).Min();


					var replaceText="\r\n".PadRight(count+2,'\t');
					t=original.Replace(replaceText, replaceText + text);
				}
				else
				{
					List<string> list=new List<string>();
					foreach (string s in original.Split(new string[]{"\r\n"},StringSplitOptions.None))
					{
						int i = 0;
						while (i<s.Length && s[i] == '\t')
						{
							i++;
						}
						if (s.Substring(i).StartsWith(Box.comment))
						{
							list.Add(s.Substring(0, i) + s.Substring(i + 2));
						}
						else
						{
							list.Add(s);
						}
					}
					t=string.Join("\r\n",list.ToArray());
				}
				this.textBox.Select(start, end - start);
				this.textBox.TextArea.Selection.ReplaceSelectionWithText(textBox.TextArea, t);
				this.textBox.Select(start+2, t.Length-2);


				//int start = textBox.Document.GetOffset(textBox.Document.GetLineByOffset(textBox.SelectionStart).LineNumber, 1);// .GetLineStartPosition(0);
				//int end = textBox.SelectionStart + textBox.SelectionLength;
				//// TODO: fix this
				//textBox.Text = textBox.Text.Substring(0, start) + ("\r\n"+textBox.Text).Substring(start,end-start).Replace("\r\n","\r\n"+text) + textBox.Text.Substring(end, textBox.Text.Length-end);
			}
			public bool Compile(bool automatic)
			{
				try
				{
					Map m;
					Parser p;
					if (Compile(textBox.Text, automatic, out m, out p))
					{
						editor.lineInfo.Content = "";
						return p.state.Errors.Count()==0;
					}
					else
					{
						string text = "";
						foreach (var x in p.state.Errors)
						{
							text += x.Text + x.Source.ToString();
						}
						editor.lineInfo.Content = "Parse error:" + text; ;
						return false;
					}
				}
				catch
				{
					return false;
				}
			}
			public void Save()
			{
				Save(false);
			}
			public void Save(bool newName)
			{
				if (fileName == null || newName)
				{
					SaveFileDialog dialog = new SaveFileDialog();
					dialog.DefaultExt = "*meta";
					dialog.Filter = "Meta files (*.meta)|*.meta";
					if (dialog.ShowDialog() == true)
					{
						fileName = dialog.FileName;
					}
					else
					{
						return;
					}
				}
				File.WriteAllText(fileName, textBox.Text);
				changes = false;
			}
			public bool changes
			{
				get
				{
					return _changes;
				}
				set
				{
					_changes=value;
					this.textBox.Parsed = null;
					if (_changes)
					{
						this.SetHeader(System.IO.Path.GetFileName(fileName) + "*");
					}
					else
					{
						this.Header=System.IO.Path.GetFileName(fileName);
					}
				}
			}
		}
		public class DebugView : TreeListView
		{
			public Map context;
			public DebugView()
			{
			}
		}
		private static void BindKey(RoutedCommand command, Key key, ModifierKeys modifiers)
		{
			command.InputGestures.Add(new KeyGesture(key, modifiers));
		}
		public static ObservableCollection<Page> pages = new ObservableCollection<Page>();
		public void Open(string file)
		{
			Page item = new Page();

			if (file != "")
			{
				item.fileName = file;

				item.SetHeader(System.IO.Path.GetFileName(file));

				item.textBox.Text = File.ReadAllText(file);
			}
			item.changes = false;
			//pages.Add(item);
			tabs.Items.Add(item);
			item.Focus();
			item.textBox.Focus();
		}
		public static int searchStart = 0;

		const string openBraces = "({[<\"";
		const string closeBraces = ")}]>\"";
		public static string DocumentationPath
		{
			get
			{
				return System.IO.Path.Combine(Interpreter.InstallationPath, "documentation.meta");
			}
		}
		public static void HideWatch()
		{
			editor.watch1.Visibility = Visibility.Collapsed;
		}

		public static void HideErrors()
		{
			editor.errorList.Visibility = Visibility.Collapsed;
		}

		public static List<Rectangle> errors = new List<Rectangle>();
		public static Replace findAndReplace;
		public class Breakpoint
		{
			public int line;
			public int column;
			public Breakpoint(int line, int column)
			{
				this.line = line;
				this.column = column;
				Ellipse point = new Ellipse();
				point.Width = 10;
				point.Height = 10;
				point.Fill = Brushes.Red;
			}
		}
		public class SubItem : TreeListViewItem
		{
			public void MakeSureComputed()
			{
				SetMap(map, true);
			}
			private StackPanel panel = new StackPanel();
			private Label key = new Label();
			private Label value = new Label();
			private Map map;
			public SubItem(Map key, Map value, bool expand)
			{
				this.key.Content = key.ToString();
				Items.Clear();
				this.map = value;
				if (expand)
				{
					SetMap(value, false);
				}
				bool wasExpanded = false;
				this.Expanded += delegate
				{
					if (!wasExpanded)
					{
						wasExpanded = true;
						MakeSureComputed();
					}
				};
				panel.Orientation = Orientation.Horizontal;
				panel.Children.Add(this.key);
				panel.Children.Add(this.value);
				this.Header = panel;
			}
			public void SetMap(Map map, bool expand)
			{
				value.Content = "";
				Items.Clear();
				if (map.IsString)
				{
					value.Content = map.GetString();
				}
				else if (map.GetNumber() != null)
				{
					this.value.Content = map.GetNumber().ToString();
				}
				else
				{
					foreach (KeyValuePair<Map, Map> entry in map)
					{
						Items.Add(new SubItem(entry.Key, entry.Value, expand));
					}
				}
			}
		}
		public static string ProgramName
		{
			get
			{
				return "Meta Edit";
			}
		}
		public static string Version
		{
			get
			{
				return "0.1";
			}
		}
		public static void LoadSettings()
		{
			using (RegistryKey key = Registry.CurrentUser.OpenSubKey("Software", true).CreateSubKey(ProgramName).CreateSubKey(Version))
			{
				foreach (FieldInfo field in typeof(Settings).GetFields())
				{
					if (field.FieldType == typeof(string[]))
					{
						List<string> values=new List<string>();
						RegistryKey subKey = key.OpenSubKey(field.Name);
						if (subKey != null)
						{
							foreach (string k in key.OpenSubKey(field.Name).GetValueNames())
							{
								values.Add((string)key.OpenSubKey(field.Name).GetValue(k));
							}
							field.SetValue(null, values.ToArray());
						}
					}
					object value=key.GetValue(field.Name, null);
					if(value!=null)
					{
						field.SetValue(null, value);
					}
				}
			}
		}
		public static void SaveSettings()
		{
			using (RegistryKey key = Registry.CurrentUser.OpenSubKey("Software", true).CreateSubKey(ProgramName).CreateSubKey(Version))
			{
				foreach (FieldInfo field in typeof(Settings).GetFields())
				{
					object value=field.GetValue(null);
					if (value is string[])
					{
						if (key.OpenSubKey(field.Name) != null)
						{
							key.DeleteSubKeyTree(field.Name);
						}
						RegistryKey k = key.CreateSubKey(field.Name);
						int count=1;
						foreach(string s in (string[])value)
						{
							if (s != null)
							{
								k.SetValue(count.ToString(), s);
							}
							count++;
						}
					}
					else
					{
						if (value != null)
						{
							key.SetValue(field.Name, value);
						}
					}
				}
			}
		}
		public static bool continueDebugging = false;

		public static string GetIndentation(string line)
		{
			line = line.Trim('\n', 'n');
			return "".PadLeft(line.Length - LineWithoutIndentation(line).Length, '\t');
		}
		public static string LineWithoutIndentation(string line)
		{
			return line.TrimStart('\t');
		}
		public class WatchItem
		{
			private TextBox expression=new TextBox();
			public TextBox Expression
			{
				get
				{
					return expression;
				}
			}
		}
		public static FontFamily font
		{
			get
			{
				return new FontFamily(Settings.Font);
			}
		}
		public static int fontSize
		{
			get
			{
				return Convert.ToInt32(Settings.FontSize);
			}
		}
		static Editor()
		{
			// TODO: move this into XAML
			//var factory=new FrameworkElementFactory(typeof(TextBox));
			//factory.SetValue(Control.BackgroundProperty, Brushes.Red);
			//factory.SetValue(TextBox.TextProperty, "hello");
			//watch1.Columns.Add(new GridViewColumn() {
			//    Header = "Name",
			//    CellTemplate = new DataTemplate()
			//    {
			//        VisualTree=factory
			//    }
			//});
			//watch1.Columns.Add(
			//    new GridViewColumn()
			//    {
			//        Header = "Value",
			//        Width = 60,
			//        CellTemplate = new DataTemplate()
			//        {
			//            VisualTree = new FrameworkElementFactory(typeof(TextBox))
			//        },
			//    }
			//);
			//watch1.Columns.Add(
			//    new GridViewColumn()
			//    {
			//        Header = "Update",
			//        CellTemplate = new DataTemplate()
			//        {
			//            VisualTree = new FrameworkElementFactory(typeof(Button))
			//        }
			//    }
			//);

			//GridView gridView = new GridView();
			//Uri errorUri = new Uri("pack://application:,,,/images/Critical.png", UriKind.RelativeOrAbsolute);

			//DataTemplate template = new DataTemplate();
			//var f = new FrameworkElementFactory(typeof(Image));
			//template.VisualTree=f;
			//template.VisualTree.SetValue(Image.SourceProperty, new BitmapImage(errorUri));

			//gridView.Columns.Add(new GridViewColumn() { Header = "", CellTemplate = template });


			//gridView.Columns.Add(new GridViewColumn() { Header = "Description", DisplayMemberBinding = new Binding("Text")});// { Path = new PropertyPath("Text") } });
			//gridView.Columns.Add(new GridViewColumn() { Header = "File", DisplayMemberBinding = new Binding("Source.FileName") });
			//gridView.Columns.Add(new GridViewColumn() { Header = "Line", DisplayMemberBinding = new Binding("Source.Line") });
			//gridView.Columns.Add(new GridViewColumn() { Header = "Column", DisplayMemberBinding = new Binding("Source.Column") });

			// TODO: make this work
			//editor.errorList = new ListView()
			//{
				//VerticalAlignment = VerticalAlignment.Stretch,
				//Background = Brushes.LightBlue,
				//Height = 100,
				//Visibility = Visibility.Collapsed,
				////View = gridView
			//};
			//editor.errorList.SelectionChanged += new SelectionChangedEventHandler(errorList_SelectionChanged);
			
		}

		void errorList_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			ListViewItem item = (ListViewItem)editor.errorList.SelectedItem;
			if (item != null)
			{
				CurrentPage.textBox.Dispatcher.BeginInvoke((System.Threading.SendOrPostCallback)delegate(object state)
				{
					Error error = (Error)state;
					CurrentPage.textBox.SelectionStart = error.Source.Index;
					CurrentPage.textBox.ScrollToLine(error.Source.Line);
					CurrentPage.textBox.Focus();
					Keyboard.Focus(CurrentPage.textBox);

				}, DispatcherPriority.Background, new object[] { item.DataContext });

			}
		}
		public void Open()
		{
			OpenFileDialog dialog = new OpenFileDialog();
			dialog.Filter = "Meta files (*.meta)|*.meta|All Files (*.*)|*.*";
			dialog.Multiselect = true;
			if (dialog.ShowDialog() == true)
			{
				foreach (var name in dialog.FileNames)
				{
					Open(name);
				}
			}
		}
	}
	public static class Text
	{
		public static char Character(this TextPointer t)
		{
			TextPointer next=t.GetNextInsertionPosition(LogicalDirection.Forward);
			if(next==null)
			{
				return char.MaxValue;
			}
			string text=new TextRange(t, next).Text;
			if (text.Length == 0)
			{
				return char.MaxValue;
			}
			return text[0];
		}
	}
	public class Settings
	{
		public static string Font = "Courier New";
		public static string FontSize = "12";
		public static string[] lastFiles;
	}

	// Stephen Toub
	// stoub@microsoft.com
	//
	// Retrieve the xml comments stored in the assembly's comments file
	// for specific types or members of types.
	public class Comments
	{

		private static Dictionary<string, XmlDocument> _assemblyDocs = new Dictionary<string, XmlDocument>();
		public static Dictionary<string, Comments> cache = new Dictionary<string, Comments>();
		private static BindingFlags _bindingFlags = BindingFlags.Instance | BindingFlags.Static |
			BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;


		public string GetSummary()
		{
			string text="";
			if (this.Summary == null)
			{
				return "";
			}
			text = GetNodeContent(this.Summary);
			return text.Trim();
		}

		private string GetNodeContent(XmlNode node)
		{
			string text = "";
			foreach (XmlNode x in node.ChildNodes)
			{
				if (x is XmlText)
				{
					text += x.InnerText;
				}
				else if (x is XmlElement)
				{
					if (x.LocalName == "see")
					{
						string t = x.Attributes["cref"].InnerText;
						int i = t.IndexOf(':');
						if (i == -1)
						{
							i = 0;
						}
						else
						{
							i++;
						}
						text += t.Substring(i);
					}
				}
			}
			return text.Trim();
		}
		public List<Inline> GetParameters()
		{
			List<Inline> runs=new List<Inline>();// Run run = new Run();
			foreach (XmlNode parameter in this.Parameters)
			{
				runs.Add(new Bold(new Run("\n"+parameter.Attributes["name"].InnerText+":")));
				runs.Add(new Run(" " + GetNodeContent(parameter)));
			}
			return runs;
		}
		public XmlNode Summary;
		public XmlNodeList Parameters;


		public static Comments GetComment(MemberInfo member)
		{
			string name = GetName(member);
			if (!cache.ContainsKey(name))
			{
				Load(member);
			}
			if (cache.ContainsKey(name))
			{
				return cache[name];
			}
			return new Comments();
		}
		public Comments()
		{
			Summary = new XmlDocument();
			Parameters = new XmlDocument().ChildNodes;
		}
		private Comments(XmlNode node)
		{
			if (node != null)
			{
				Summary = node.SelectSingleNode("summary");
				Parameters = node.SelectNodes("param");
			}
		}
		private static string GetName(MemberInfo mi)
		{
			Type declType = (mi is Type) ? ((Type)mi) : mi.DeclaringType;
			string typeName = declType.FullName.Replace("+", ".");
			switch (mi.MemberType)
			{
				case MemberTypes.NestedType:
				case MemberTypes.TypeInfo:
					return "T:" + typeName;
				case MemberTypes.Constructor:
					return "M:" + typeName + "." + "#ctor" +
						CreateParamsDescription(((ConstructorInfo)mi).GetParameters());
				case MemberTypes.Method:
					string text = "M:" + typeName + "." +
						mi.Name + CreateParamsDescription(((MethodInfo)mi).GetParameters());
					//if (mi.Name == "op_Implicit" || mi.Name == "op_Explicit") {
					//    xpath += "~{" + ((MethodInfo)mi).ReturnType.FullName + "}";
					//}
					return text;
				case MemberTypes.Property:
					return "P:" + typeName + "." +
						mi.Name + CreateParamsDescription(((PropertyInfo)mi).GetIndexParameters());
				case MemberTypes.Field:
					return "F:" + typeName + "." + mi.Name;
				case MemberTypes.Event:
					return "E:" + typeName + "." + mi.Name;
				default:
					throw new Exception("unknown member type");
			}
		}
		public static void Load(MemberInfo member)
		{
			Assembly assembly = member.Module.Assembly;
			if (!_assemblyDocs.ContainsKey(assembly.FullName))
			{
				XmlDocument document = LoadAssemblyComments(assembly);
				if (document != null)
				{
					foreach (XmlNode node in document.SelectSingleNode("/doc/members").ChildNodes)
					{
						cache[node.Attributes["name"].Value] = new Comments(node);
					}
				}
			}
		}
		private static string CreateParamsDescription(ParameterInfo[] parameters)
		{
			StringBuilder paramDesc = new StringBuilder();

			// If there are parameters then we need to construct a list
			if (parameters.Length > 0)
			{
				// Start the list
				paramDesc.Append("(");

				// For each parameter, append the type of the parameter.
				// Separate all items with commas.
				for (int i = 0; i < parameters.Length; i++)
				{
					Type paramType = parameters[i].ParameterType;
					string paramName = paramType.FullName;
					if (paramName == null)
					{
						paramName = "noName";
					}

					// Handle special case where ref parameter ends in & but xml docs use @.
					// Pointer parameters end in * in both type representation and xml comments representation.
					if (paramName.EndsWith("&"))
						paramName = paramName.Substring(0, paramName.Length - 1) + "@";

					if (paramType.IsArray && paramType.GetArrayRank() > 1)
					{
						paramName = paramName.Replace(",", "0:,").Replace("]", "0:]");
					}
					paramDesc.Append(paramName);
					if (i != parameters.Length - 1)
						paramDesc.Append(",");
				}
				paramDesc.Append(")");
			}
			return paramDesc.ToString();
		}

		public static XmlDocument LoadAssemblyComments(Assembly a)
		{
			XmlDocument doc;
			if (!_assemblyDocs.ContainsKey(a.FullName))
			{
				string xmlPath = DetermineXmlPath(a);
				if (xmlPath == null)
					return null;

				// Load it and store it
				doc = new XmlDocument();
				doc.Load(xmlPath);
				_assemblyDocs[a.FullName] = doc;
			}
			else
			{
				doc = (XmlDocument)_assemblyDocs[a.FullName];
			}
			return doc;
		}
		static string ProgramFilesx86() { 
			if (8 == IntPtr.Size || (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432")))) 
			{ 
				return Environment.GetEnvironmentVariable("ProgramFiles(x86)"); 
			} 
			return Environment.GetEnvironmentVariable("ProgramFiles"); 
		}
		private static string DetermineXmlPath(Assembly asm)
		{
			// TODO: fix search path
			string[] locations = new string[] {   
				asm.Location,
				//System.IO.Path.Combine(System.IO.Path.Combine(ProgramFilesx86(),@"Reference Assemblies\Microsoft\Framework\v3.5\"),System.IO.Path.GetFileName(asm.CodeBase)),
				//System.IO.Path.Combine(System.IO.Path.Combine(ProgramFilesx86(),@"Reference Assemblies\Microsoft\Framework\v3.0\en\"),System.IO.Path.GetFileName(asm.CodeBase)),
				@"C:\Windows\Microsoft.NET\Framework\v2.0.50727\en",
				//System.IO.Path.Combine( System.IO.Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(),"en"),System.IO.Path.GetFileName(asm.CodeBase)),
            };

			//string[] locations = new string[] {   
			//    asm.Location,
			//    System.IO.Path.Combine(System.IO.Path.Combine(ProgramFilesx86(),@"Reference Assemblies\Microsoft\Framework\v3.5\"),System.IO.Path.GetFileName(asm.CodeBase)),
			//    System.IO.Path.Combine(System.IO.Path.Combine(ProgramFilesx86(),@"Reference Assemblies\Microsoft\Framework\v3.0\en\"),System.IO.Path.GetFileName(asm.CodeBase)),
			//    @"C:\Windows\Microsoft.NET\Framework\v2.0.50727\en",
			//    System.IO.Path.Combine( System.IO.Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(),"en"),System.IO.Path.GetFileName(asm.CodeBase)),
			//};

			foreach (string location in locations)
			{
				string newPath = System.IO.Path.ChangeExtension(System.IO.Path.Combine(location,System.IO.Path.GetFileName(asm.CodeBase)), ".xml");//.Replace("Framework64","Framework");
				if (File.Exists(newPath))
					return newPath;
			}
			return null;
		}
	}
	public class TreeListView : TreeView
	{
		protected override DependencyObject GetContainerForItemOverride()
		{
			return new TreeListViewItem();
		}

		protected override bool IsItemItsOwnContainerOverride(object item)
		{
			return item is TreeListViewItem;
		}

		#region Public Properties
		public GridViewColumnCollection Columns
		{
			get
			{
				if (_columns == null)
				{
					_columns = new GridViewColumnCollection();
				}

				return _columns;
			}
		}

		private GridViewColumnCollection _columns;

		#endregion
	}
	public class LevelToIndentConverter : IValueConverter
	{
		public object Convert(object o, Type type, object parameter, CultureInfo culture)
		{
			return new Thickness((int)o * c_IndentSize, 0, 0, 0);
		}

		public object ConvertBack(object o, Type type, object parameter, CultureInfo culture)
		{
			throw new NotSupportedException();
		}

		private const double c_IndentSize = 19.0;
	}
	public class TreeListViewItem : TreeViewItem
	{
		public int Level
		{
			get
			{
				if (_level == -1)
				{
					TreeListViewItem parent = ItemsControl.ItemsControlFromItemContainer(this) as TreeListViewItem;
					_level = (parent != null) ? parent.Level + 1 : 0;
				}
				return _level;
			}
		}
		protected override DependencyObject GetContainerForItemOverride()
		{
			return new TreeListViewItem();
		}
		protected override bool IsItemItsOwnContainerOverride(object item)
		{
			return item is TreeListViewItem;
		}
		private int _level = -1;
	}
}
